Railway Operation Simulator  v2.20.2
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 #include <windows.h>
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "TrainUnit.h"
45 #include "GraphicUnit.h"
46 //#include "DisplayUnit.h" included in TrackUnit.h
47 #include "TextUnit.h"
48 #include "PerfLogUnit.h"
49 #include "Utilities.h"
50 
51 #pragma package(smart_init)
52 // ---------------------------------------------------------------------------
53 
56 
57 // ---------------------------------------------------------------------------
58 
59 // FIXED TRACK :-
60 
61 // Constructor to build TrackPieces from array
62 
63 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
64  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
65 {
66  for(int x = 0; x < 4; x++)
67  {
68  Link[x] = LkVal[x];
69  Config[x] = ConfigVal[x];
70  }
71 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
72  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
73  if(SpeedTagVal == 76)
74  {
76  }
77  else if(SpeedTagVal == 77)
78  {
80  }
81  else if(SpeedTagVal == 78)
82  {
84  }
85  else if(SpeedTagVal == 79)
86  {
88  }
89  else if(SpeedTagVal == 96)
90  {
92  }
93  else if(SpeedTagVal == 129)
94  {
96  }
97  else if(SpeedTagVal == 130)
98  {
100  }
101  else if(SpeedTagVal == 131)
102  {
104  }
105  else if(SpeedTagVal == 145)
106  {
108  }
109  else if(SpeedTagVal == 146)
110  {
112  }
113 }
114 
115 // ---------------------------------------------------------------------------
116 
117 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
118  FixedNamedLocationElement(false) // default values
119 {
120  for(int x = 0; x < 4; x++)
121  {
122  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
123  Config[x] = NotSet;
124  }
125 }
126 
127 // ---------------------------------------------------------------------------
128 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
129 {
130  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
131  AnsiString(VLocInput));
132  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
133  Utilities->CallLogPop(1331);
134 }
135 
136 // ---------------------------------------------------------------------------
137 
138 // VARIABLE TRACK :-
139 
140 // ---------------------------------------------------------------------------
141 
143 {
144  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
145  {
146  return(true);
147  }
148  else
149  {
150  return(false);
151  }
152 }
153 
154 // ---------------------------------------------------------------------------
155 
157 {
158  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
159  {
160  return(true);
161  }
162  else
163  {
164  return(false);
165  }
166 }
167 
168 // ---------------------------------------------------------------------------
169 
171 // 'Variable' in the sense that element might be striped or non-striped
172 {
173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
174  Graphics::TBitmap *GraphicOutput = GraphicPtr;
175 
176  if(LocationName == "")
177  {
178  switch(SpeedTag)
179  {
180  case 76: // t platform
181  GraphicOutput = RailGraphics->gl76Striped;
182  break;
183 
184  case 77: // h platform
185  GraphicOutput = RailGraphics->bm77Striped;
186  break;
187 
188  case 78: // v platform
189  GraphicOutput = RailGraphics->bm78Striped;
190  break;
191 
192  case 79: // r platform
193  GraphicOutput = RailGraphics->gl79Striped;
194  break;
195 
196  case 96: // concourse
197  GraphicOutput = RailGraphics->ConcourseStriped;
198  break;
199 
200  case 129: // v footbridge
201  GraphicOutput = RailGraphics->gl129Striped;
202  break;
203 
204  case 130: // h footbridge
205  GraphicOutput = RailGraphics->gl130Striped;
206  break;
207 
208  case 131: // non-station named loc
209  GraphicOutput = RailGraphics->bmNameStriped;
210  break;
211 
212  case 145: // v underpass
213  GraphicOutput = RailGraphics->gl145Striped;
214  break;
215 
216  case 146: // h underpass
217  GraphicOutput = RailGraphics->gl146Striped;
218  break;
219 
220  default:
221  GraphicOutput = GraphicPtr;
222  break;
223  }
224  }
225  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
226  //deal with TSRs
227  if((TrackType == Simple) && Failed) //added at v2.13.0
228  {
229  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
230  }
231  Utilities->CallLogPop(1332);
232 }
233 
234 // ---------------------------------------------------------------------------
235 
236 AnsiString TTrackElement::LogTrack(int Caller) const
237 // for debugging when passes as a call parameter
238 {
239  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
240  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
241 
242  return(LogString);
243 }
244 
245 // ---------------------------------------------------------------------------
246 
248  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
249  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
250  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1),
251  StationEntryStopLinkPos2(-1), StationEntryStopLinkPos3(-1), StationEntryStopLinkPos4(-1), SigAspect(FourAspect)
252  {
253  Failed = false; //added at v2.13.0
254  for(int x = 0; x < 4; x++)
255  {
256  ConnLinkPos[x] = -1;
257  Conn[x] = -1;
258  }
259  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
260  {
263  }
264  }
265 
266 // ---------------------------------------------------------------------------
267 
268 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
269 {
270  if(lower.second < higher.second)
271  {
272  return(true);
273  }
274  else if(lower.second > higher.second)
275  {
276  return(false);
277  }
278  else if(lower.second == higher.second)
279  {
280  if(lower.first < higher.first)
281  {
282  return(true);
283  }
284  }
285  return(false);
286 }
287 
288 // ---------------------------------------------------------------------------
289 // PrefDirElement Functions
290 // ---------------------------------------------------------------------------
291 
292 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
293  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
294  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
295 {
296  if(!EntryExitNumber())
297  {
298  throw Exception("EXNumber failure in TPrefDirElement constructor");
299  }
302 }
303 
304 // ---------------------------------------------------------------------------
305 
306 AnsiString TPrefDirElement::LogPrefDir() const
307 // for debugging when passed as a call parameter
308 {
309  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
310  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
311  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
313 
314 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
315  return(LogString);
316 }
317 
318 // ---------------------------------------------------------------------------
319 
320 bool TPrefDirElement::EntryExitNumber() // true for valid number
321 /*
322  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
323  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
324  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
325  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
326  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
327  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
328  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
329  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
330  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
331 */
332 
333 {
334  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
335  int EXArray[16][2] =
336  {{4, 6}, {2, 8}, // horizontal & vertical
337  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
338  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
339  {1, 9}, {3, 7}}; // forward & reverse diagonals
340 
341  int EXNum = -1;
342  int Entry, Exit;
343 
344  if(ELink > -1)
345  {
346  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
347  }
348  else if(Link[2] == -1)
349  {
350  Entry = Link[0];
351  }
352  else
353  {
354  Utilities->CallLogPop(122);
355  return(false);
356  }
357  if(XLink > -1)
358  {
359  Exit = XLink;
360  }
361  else if(Link[2] == -1)
362  {
363  Exit = Link[1];
364  }
365  else
366  {
367  Utilities->CallLogPop(123);
368  return(false);
369  }
370  for(int x = 0; x < 16; x++)
371  {
372  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
373  {
374  EXNum = x;
375  }
376  }
377  if(EXNum == -1)
378  {
379  Utilities->CallLogPop(124);
380  return(false);
381  }
382  int BrNum = -1;
383 
384 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
385  the graphic for each of which is different because of the shape of the overbridge. The basic
386  entry/exit value is computed above, and this used to select only from elements with that entry/exit
387  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
388  int BrEXArray[24][2] = {
389  {4,6},{2,8},{1,9},{3,7},
390  {1,9},{3,7},{1,9},{3,7},
391  {2,8},{4,6},{2,8},{4,6}
392 */
393 
394  if(TrackType == Bridge)
395  {
396  if(EXNum == 1)
397  {
398  if(SpeedTag == 49)
399  {
400  BrNum = 1 + 16;
401  }
402  else if(SpeedTag == 54)
403  {
404  BrNum = 8 + 16;
405  }
406  else if(SpeedTag == 55)
407  {
408  BrNum = 10 + 16;
409  }
410  }
411  else if(EXNum == 0)
412  {
413  if(SpeedTag == 48)
414  {
415  BrNum = 0 + 16;
416  }
417  else if(SpeedTag == 58)
418  {
419  BrNum = 11 + 16;
420  }
421  else if(SpeedTag == 59)
422  {
423  BrNum = 9 + 16;
424  }
425  }
426  else if(EXNum == 14)
427  {
428  if(SpeedTag == 50)
429  {
430  BrNum = 2 + 16;
431  }
432  else if(SpeedTag == 52)
433  {
434  BrNum = 4 + 16;
435  }
436  else if(SpeedTag == 57)
437  {
438  BrNum = 6 + 16;
439  }
440  }
441  else if(EXNum == 15)
442  {
443  if(SpeedTag == 51)
444  {
445  BrNum = 3 + 16;
446  }
447  else if(SpeedTag == 53)
448  {
449  BrNum = 7 + 16;
450  }
451  else if(SpeedTag == 56)
452  {
453  BrNum = 5 + 16;
454  }
455  }
456  }
457  if(BrNum == -1)
458  {
459  EXNumber = EXNum;
460  }
461  else
462  {
463  EXNumber = BrNum;
464  }
465  Utilities->CallLogPop(125);
466  return(true);
467 }
468 
469 // ---------------------------------------------------------------------------
470 
472 /*
473  This is the basic track graphic for use in plotting the original graphic during route flashing.
474  Enter with all set apart from EXGraphic & EntryDirectionGraphic
475 */
476 {
477  if(SpeedTag == 64)
478  {
479  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
480 
481  }
482  if(SpeedTag == 65)
483  {
484  return(RailGraphics->LinkGraphicsPtr[17]);
485  }
486  if(SpeedTag == 66)
487  {
488  return(RailGraphics->LinkGraphicsPtr[18]);
489  }
490  if(SpeedTag == 67)
491  {
492  return(RailGraphics->LinkGraphicsPtr[19]);
493  }
494  if(SpeedTag == 80)
495  {
496  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
497 
498  }
499  if(SpeedTag == 81)
500  {
501  return(RailGraphics->LinkGraphicsPtr[21]);
502  }
503  if(SpeedTag == 82)
504  {
505  return(RailGraphics->LinkGraphicsPtr[22]);
506  }
507  if(SpeedTag == 83)
508  {
509  return(RailGraphics->LinkGraphicsPtr[23]);
510  }
511  if(SpeedTag == 84)
512  {
513  return(RailGraphics->LinkGraphicsPtr[24]);
514  }
515  if(SpeedTag == 85)
516  {
517  return(RailGraphics->LinkGraphicsPtr[25]);
518  }
519  if(SpeedTag == 86)
520  {
521  return(RailGraphics->LinkGraphicsPtr[26]);
522  }
523  if(SpeedTag == 87)
524  {
525  return(RailGraphics->LinkGraphicsPtr[27]);
526  }
527  if(SpeedTag == 129)
528  {
529  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
530 
531  }
532  if(SpeedTag == 130)
533  {
534  return(RailGraphics->LinkGraphicsPtr[29]);
535  }
536  if(XLinkPos == -1) // not set, could be first element or last element = leading point
537  {
538 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
539 // Points & don't want to display these)
540  if(Link[2] != -1)
541  {
542  return(0); // i.e. complex element, don't display
543  }
544  else
545  {
546  if(!EntryExitNumber())
547  {
548  throw Exception("Error in EntryExitNumber 4");
549  }
550  else
551  {
553  }
554  }
555  }
556  if(EXNumber > 15) // underbridge
557  {
558  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
559  }
560  else
561  {
563  }
564 }
565 
566 // ---------------------------------------------------------------------------
567 
569 /*
570  As above but for PrefDir graphics.
571 */
572 {
573  if(SpeedTag == 64)
574  {
575  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
576 
577  }
578  if(SpeedTag == 65)
579  {
581  }
582  if(SpeedTag == 66)
583  {
585  }
586  if(SpeedTag == 67)
587  {
589  }
590  if(SpeedTag == 80)
591  {
592  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
593 
594  }
595  if(SpeedTag == 81)
596  {
598  }
599  if(SpeedTag == 82)
600  {
602  }
603  if(SpeedTag == 83)
604  {
606  }
607  if(SpeedTag == 84)
608  {
610  }
611  if(SpeedTag == 85)
612  {
614  }
615  if(SpeedTag == 86)
616  {
618  }
619  if(SpeedTag == 87)
620  {
622  }
623  if(SpeedTag == 129)
624  {
625  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
626 
627  }
628  if(SpeedTag == 130)
629  {
631  }
632  if(XLinkPos == -1) // not set, could be first element or last element = leading point
633  {
634 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
635  if(Link[2] != -1)
636  {
637  return(0); // i.e. complex element, don't display
638  }
639  else
640  {
641  if(!EntryExitNumber())
642  {
643  throw Exception("Error in EntryExitNumber 5");
644  }
645  else
646  {
648  }
649  }
650  }
651  if(EXNumber > 15) // underbridge
652  {
654  }
655  else
656  {
658  }
659 }
660 
661 // ---------------------------------------------------------------------------
662 
663 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
664 /*
665  As above but for route graphics.
666 */
667 {
668  if(!AutoSigsFlag && !PrefDirRoute)
669  {
670  if(SpeedTag == 64)
671  {
672  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
673  }
674  if(SpeedTag == 65)
675  {
677  }
678  if(SpeedTag == 66)
679  {
681  }
682  if(SpeedTag == 67)
683  {
685  }
686  if(SpeedTag == 80)
687  {
688  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
689  }
690  if(SpeedTag == 81)
691  {
693  }
694  if(SpeedTag == 82)
695  {
697  }
698  if(SpeedTag == 83)
699  {
701  }
702  if(SpeedTag == 84)
703  {
705  }
706  if(SpeedTag == 85)
707  {
709  }
710  if(SpeedTag == 86)
711  {
713  }
714  if(SpeedTag == 87)
715  {
717  }
718  if(SpeedTag == 129)
719  {
720  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
721  }
722  if(SpeedTag == 130)
723  {
725  }
726  if(XLinkPos == -1) // not set, could be first element or last element = leading point
727  {
728  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
729  if(Link[2] != -1)
730  {
731  return(0); // i.e. complex element, don't display
732  }
733  else
734  {
735  if(!EntryExitNumber())
736  {
737  throw Exception("Error in EntryExitNumber 6");
738  }
739  else
740  {
742  }
743  }
744  }
745  if(EXNumber > 15) // underbridge
746  {
748  }
749  else
750  {
752  }
753  }
754 
755  else if(!AutoSigsFlag && PrefDirRoute)
756  {
757  if(SpeedTag == 64)
758  {
759  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
760  }
761  if(SpeedTag == 65)
762  {
764  }
765  if(SpeedTag == 66)
766  {
768  }
769  if(SpeedTag == 67)
770  {
772  }
773  if(SpeedTag == 80)
774  {
775  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
776  }
777  if(SpeedTag == 81)
778  {
780  }
781  if(SpeedTag == 82)
782  {
784  }
785  if(SpeedTag == 83)
786  {
788  }
789  if(SpeedTag == 84)
790  {
792  }
793  if(SpeedTag == 85)
794  {
796  }
797  if(SpeedTag == 86)
798  {
800  }
801  if(SpeedTag == 87)
802  {
804  }
805  if(SpeedTag == 129)
806  {
807  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
808  }
809  if(SpeedTag == 130)
810  {
812  }
813  if(XLinkPos == -1) // not set, could be first element or last element = leading point
814  {
815  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
816  if(Link[2] != -1)
817  {
818  return(0); // i.e. complex element, don't display
819  }
820  else
821  {
822  if(!EntryExitNumber())
823  {
824  throw Exception("Error in EntryExitNumber 10");
825  }
826  else
827  {
829  }
830  }
831  }
832  if(EXNumber > 15) // underbridge
833  {
835  }
836  else
837  {
839  }
840  }
841 
842  else
843  {
844  if(SpeedTag == 64)
845  {
846  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
847  }
848  if(SpeedTag == 65)
849  {
851  }
852  if(SpeedTag == 66)
853  {
855  }
856  if(SpeedTag == 67)
857  {
859  }
860  if(SpeedTag == 80)
861  {
862  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
863 
864  }
865  if(SpeedTag == 81)
866  {
868  }
869  if(SpeedTag == 82)
870  {
872  }
873  if(SpeedTag == 83)
874  {
876  }
877  if(SpeedTag == 84)
878  {
880  }
881  if(SpeedTag == 85)
882  {
884  }
885  if(SpeedTag == 86)
886  {
888  }
889  if(SpeedTag == 87)
890  {
892  }
893  if(SpeedTag == 129)
894  {
895  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
896 
897  }
898  if(SpeedTag == 130)
899  {
901  }
902  if(XLinkPos == -1) // not set, could be first element or last element = leading point
903  {
904  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
905  if(Link[2] != -1)
906  {
907  return(0); // i.e. complex element, don't display
908  }
909  else
910  {
911  if(!EntryExitNumber())
912  {
913  throw Exception("Error in EntryExitNumber 11");
914  }
915  else
916  {
918  }
919  }
920  }
921  if(EXNumber > 15) // underbridge
922  {
924  }
925  else
926  {
928  }
929  }
930 }
931 
932 // ---------------------------------------------------------------------------
933 
935 /*
936  As above but for route flashing graphics. (Disused - now combined with above)
937 */
938 {
939  if(SpeedTag == 64)
940  {
941  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
942 
943  }
944  if(SpeedTag == 65)
945  {
947  }
948  if(SpeedTag == 66)
949  {
951  }
952  if(SpeedTag == 67)
953  {
955  }
956  if(SpeedTag == 80)
957  {
958  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
959 
960  }
961  if(SpeedTag == 81)
962  {
964  }
965  if(SpeedTag == 82)
966  {
968  }
969  if(SpeedTag == 83)
970  {
972  }
973  if(SpeedTag == 84)
974  {
976  }
977  if(SpeedTag == 85)
978  {
980  }
981  if(SpeedTag == 86)
982  {
984  }
985  if(SpeedTag == 87)
986  {
988  }
989  if(SpeedTag == 129)
990  {
991  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
992 
993  }
994  if(SpeedTag == 130)
995  {
997  }
998  if(XLinkPos == -1) // not set, could be first element or last element = leading point
999  {
1000 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1001  if(Link[2] != -1)
1002  {
1003  return(0); // i.e. complex element, don't display
1004  }
1005  else
1006  {
1007  if(!EntryExitNumber())
1008  {
1009  throw Exception("Error in EntryExitNumber 7");
1010  }
1011  else
1012  {
1014  }
1015  }
1016  }
1017  if(EXNumber > 15) // underbridge
1018  {
1020  }
1021  else
1022  {
1024  }
1025 }
1026 
1027 // ---------------------------------------------------------------------------
1028 
1030 /*
1031  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1032 */
1033 {
1034  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1035  {
1037  }
1038  else
1039  {
1040  throw Exception("Error in EntryExitNumber 8");
1041  }
1042 }
1043 
1044 // ---------------------------------------------------------------------------
1045 
1046 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1047 /*
1048  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1049 */
1050 {
1051  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1052  {
1053  if(!AutoSigsFlag && !PrefDirRoute)
1054  {
1056  }
1057  else if(!AutoSigsFlag && PrefDirRoute)
1058  {
1060  }
1061  else
1062  {
1064  }
1065  }
1066  else
1067  {
1068  throw Exception("Error in EntryExitNumber 9");
1069  }
1070 }
1071 
1072 // ---------------------------------------------------------------------------
1073 
1075 /*
1076  Set == operator when TrackVectorPosition, ELink & XLink all same
1077 */
1078 {
1079  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1080  {
1081  return(true);
1082  }
1083  else
1084  {
1085  return(false);
1086  }
1087 }
1088 
1089 // ---------------------------------------------------------------------------
1090 
1092 /*
1093  Set != operator when any of TrackVectorPosition, ELink or XLink different
1094 */
1095 {
1096  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1097  {
1098  return(false);
1099  }
1100  else
1101  {
1102  return(true);
1103  }
1104 }
1105 
1106 // ---------------------------------------------------------------------------
1107 
1108 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1109 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1110  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1111  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1112  {
1113  Utilities->CallLogPop(2566);
1114  return(1);
1115  }
1116  if(GetRouteGraphicPtr(0,1) == EXG)
1117  {
1118  Utilities->CallLogPop(2567);
1119  return(2);
1120  }
1121  if(GetRouteGraphicPtr(1,0) == EXG)
1122  {
1123  Utilities->CallLogPop(2568);
1124  return(3);
1125  }
1126  if(GetRouteGraphicPtr(1,1) == EXG)
1127  {
1128  Utilities->CallLogPop(2569);
1129  return(3);
1130  }
1131  Utilities->CallLogPop(2570);
1132  return(0);
1133 }
1134 
1135 // ---------------------------------------------------------------------------
1136 // Track functions
1137 // ---------------------------------------------------------------------------
1138 
1139 // ---------------------------------------------------------------------------
1140 
1142 {
1143  TypeOfRoute = 0;
1144  ReducedTimePenalty = false;
1145  BarrierState = Up;
1146  ChangeDuration = 0.0;
1147  BaseElementSpeedTag = 1;
1148  HLoc = 0;
1149  VLoc = 0;
1150  StartTime = TDateTime(0);
1151 }
1152 
1153 // ---------------------------------------------------------------------------
1154 
1156 {
1157 // CurrentSpeedButtonTag = 0; //not assigned yet
1158 
1159  HLocMin = 2000000000;
1160  VLocMin = 2000000000;
1161  HLocMax = -2000000000;
1162  VLocMax = -2000000000;
1163  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1164  CopyFlag = false; // only true for copying, so names aren't copied
1165  AnsiString NL = '\n';
1166 
1167  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1168  "reachable but too far ahead or with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1169  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1170  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1171 
1176 
1177  int InternalLinkCheckArray[9][2] =
1178  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1179 
1180 /* array of valid link values for 'old' location and 'new' location, where
1181  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1182 
1183  for(int x = 0; x < 9; x++)
1184  {
1185  for(int y = 0; y < 2; y++)
1186  {
1187  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1188  }
1189  }
1190 
1191 // Platform and default track element values
1192  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1193 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1194  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1195  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1196  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1197  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16 << 18 << 19 << 20 << 21 << 22 << 23 << 24
1198  << 25 << 26 << 27 << 28 << 29 << 30 << 31 << 32 << 33 << 34 << 35 << 36 << 37 << 38 << 39 << 40 << 41 << 42 << 43 << 44 << 45 << 46 << 47
1199  << 60 << 61 << 62 << 63 << 64 << 65 << 66 << 67 << 68 << 69 << 70 << 71 << 72 << 73 << 74 << 75 << 80 << 81 << 82 << 83 << 84 << 85 << 86
1200  << 87 << 125 << 126 << 127 << 128 << 132 << 133 << 134 << 135 << 136 << 137 << 138 << 139
1201  << 140 << 141 << 142 << 143; //prevent bridges, footcrossings, platforms, concourses, non-station named locs, parapets, level crossings & gaps
1202  //gaps cause a mass of problems as links not adjacent - interferes with cut/copy/paste & duplicate names found
1203  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1204 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1205 
1206  int HVArray[10][2] =
1207  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1208 
1209  for(int x = 0; x < 10; x++)
1210  {
1211  for(int y = 0; y < 2; y++)
1212  {
1213  LinkHVArray[x][y] = HVArray[x][y];
1214  }
1215  }
1216  TrackFinished = false;
1217 // DistancesSet = false;
1218 
1219  TSigElement TempSigTable[40] = // original four aspect
1220  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1221  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1222 
1223  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1224  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1225 
1228 
1229  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1230  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1231 
1232  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1233  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1234  {75, 4, RailGraphics->gl75}};
1235 
1236  for(int x = 0; x < 40; x++)
1237  {
1238  SigTable[x] = TempSigTable[x];
1239  }
1240 
1241  TSigElement TempSigTableThreeAspect[40] =
1242  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1243  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1244 
1245  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1246  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1247 
1248  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1249  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1250 
1251  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1252  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1253 
1254  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1255  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1256  {75, 4, RailGraphics->gl75}};
1257 
1258  for(int x = 0; x < 40; x++)
1259  {
1260  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1261  }
1262 
1263  TSigElement TempSigTableTwoAspect[40] =
1264  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1265  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1266 
1267  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1268  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1269 
1270  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1271  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1272 
1273  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1274  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1275 
1276  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1277  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1278  {75, 4, RailGraphics->gl75}};
1279 
1280  for(int x = 0; x < 40; x++)
1281  {
1282  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1283  }
1284 
1285  TSigElement TempSigTableGroundSignal[40] =
1289 
1293 
1297 
1301 
1302  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1305 
1306  for(int x = 0; x < 40; x++)
1307  {
1308  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1309  }
1310 
1311  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1312  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1313  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1314 
1315  for(int x = 0; x < 8; x++)
1316  {
1317  FailedSigTable[x] = TempFailedSigTable[x];
1318  }
1319 
1320  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1321  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1322  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1323 
1324  for(int x = 0; x < 8; x++)
1325  {
1326  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1327  }
1328 
1329 /*
1330  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1331  a single location. These are as follows:-
1332  Directly Adjacent = up, down, left or right - NOT diagonal.
1333  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1334  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1335  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1336 
1337  //t 76
1338  //b 77
1339  //l 78
1340  //r 79
1341  //c 96
1342  //v fb 129
1343  //h fb 130
1344  //v underpass 145
1345  //h underpass 146
1346  //n 131
1347 */
1348 
1349  int Tag76[25][3] =
1350  {{-1, 0, 96}, // c top plat
1351  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1352  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1353  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1354  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1355  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1356  {0, 0, 129}, {0, -1, 145}, // v up
1357  {0, 0, 145}};
1358 
1359  for(int x = 0; x < 25; x++)
1360  {
1361  for(int y = 0; y < 3; y++)
1362  {
1363  Tag76Array[x][y] = Tag76[x][y];
1364  }
1365  }
1366 
1367  int Tag77[25][3] =
1368  {{-1, 0, 96}, // c bot plat
1369  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1370  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1371  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1372  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1373  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1374  {0, 0, 129}, {0, 1, 145}, // v up
1375  {0, 0, 145}};
1376 
1377  for(int x = 0; x < 25; x++)
1378  {
1379  for(int y = 0; y < 3; y++)
1380  {
1381  Tag77Array[x][y] = Tag77[x][y];
1382  }
1383  }
1384 
1385  int Tag78[25][3] =
1386  {{-1, 0, 96}, // c left plat
1387  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1388  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1389  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1390  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1391  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1392  {0, 0, 130}, {-1, 0, 146}, // h up
1393  {0, 0, 146}};
1394 
1395  for(int x = 0; x < 25; x++)
1396  {
1397  for(int y = 0; y < 3; y++)
1398  {
1399  Tag78Array[x][y] = Tag78[x][y];
1400  }
1401  }
1402 
1403  int Tag79[25][3] =
1404  {{-1, 0, 96}, // c right plat
1405  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1406  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1407  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1408  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1409  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1410  {0, 0, 130}, {1, 0, 146}, // h up
1411  {0, 0, 146}};
1412 
1413  for(int x = 0; x < 25; x++)
1414  {
1415  for(int y = 0; y < 3; y++)
1416  {
1417  Tag79Array[x][y] = Tag79[x][y];
1418  }
1419  }
1420 
1421  int Tag96[28][3] =
1422  {{-1, 0, 96}, // c //concourse
1423  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1424  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1425  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1426  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1427  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1428  {0, -1, 129}, {1, 0, 130}, // h fb
1429  {-1, 0, 130}, {0, 1, 145}, // v up
1430  {0, -1, 145}, {1, 0, 146}, // h up
1431  {-1, 0, 146}};
1432 
1433  for(int x = 0; x < 28; x++)
1434  {
1435  for(int y = 0; y < 3; y++)
1436  {
1437  Tag96Array[x][y] = Tag96[x][y];
1438  }
1439  }
1440 
1441  int Tag129[8][3] = // vert fb
1442  {{0, -1, 96}, // c
1443  {0, -1, 77}, // b
1444  {0, -1, 129}, // v fb
1445 
1446  {0, 1, 96}, // c
1447  {0, 1, 76}, // t
1448  {0, 1, 129}, // v fb
1449 
1450  {0, 0, 76}, // t
1451  {0, 0, 77}}; // b
1452 
1453  for(int x = 0; x < 8; x++)
1454  {
1455  for(int y = 0; y < 3; y++)
1456  {
1457  Tag129Array[x][y] = Tag129[x][y];
1458  }
1459  }
1460 
1461  int Tag145[8][3] = // vert up
1462  {{0, -1, 96}, // c
1463  {0, -1, 77}, // b
1464  {0, -1, 145}, // v fb
1465 
1466  {0, 1, 96}, // c
1467  {0, 1, 76}, // t
1468  {0, 1, 145}, // v fb
1469 
1470  {0, 0, 76}, // t
1471  {0, 0, 77}}; // b
1472 
1473  for(int x = 0; x < 8; x++)
1474  {
1475  for(int y = 0; y < 3; y++)
1476  {
1477  Tag145Array[x][y] = Tag145[x][y];
1478  }
1479  }
1480 
1481  int Tag130[8][3] = // hor fb
1482  {{-1, 0, 96}, // c
1483  {-1, 0, 79}, // r
1484  {-1, 0, 130}, // h fb
1485 
1486  {1, 0, 96}, // c
1487  {1, 0, 78}, // l
1488  {1, 0, 130}, // h fb
1489 
1490  {0, 0, 78}, // l
1491  {0, 0, 79}}; // r
1492 
1493  for(int x = 0; x < 8; x++)
1494  {
1495  for(int y = 0; y < 3; y++)
1496  {
1497  Tag130Array[x][y] = Tag130[x][y];
1498  }
1499  }
1500 
1501  int Tag146[8][3] = // hor up
1502  {{-1, 0, 96}, // c
1503  {-1, 0, 79}, // r
1504  {-1, 0, 146}, // h fb
1505 
1506  {1, 0, 96}, // c
1507  {1, 0, 78}, // l
1508  {1, 0, 146}, // h fb
1509 
1510  {0, 0, 78}, // l
1511  {0, 0, 79}}; // r
1512 
1513  for(int x = 0; x < 8; x++)
1514  {
1515  for(int y = 0; y < 3; y++)
1516  {
1517  Tag146Array[x][y] = Tag146[x][y];
1518  }
1519  }
1520 
1521  int Tag131[4][3] =
1522  {{-1, 0, 131}, // n
1523  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1524 
1525  for(int x = 0; x < 4; x++)
1526  {
1527  for(int y = 0; y < 3; y++)
1528  {
1529  Tag131Array[x][y] = Tag131[x][y];
1530  }
1531  }
1532 
1533  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1534  {
1535  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1536  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1537  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1538  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1539  140, 144, 145, 146
1540  };
1541 
1542  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1543  {
1544  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1545  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1546  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1547  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1548  141, 144, 145, 146
1549  };
1550 
1551  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1552  {
1553  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1554  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1555  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1556  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1557  141, 144, 146, 145
1558  };
1559 
1560  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1561  {
1562  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1563  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1564  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1565  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1566  140, 144, 146, 145
1567  };
1568 
1569  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1570  {
1571  FlipArray[x] = InternalFlipArray[x];
1572  MirrorArray[x] = InternalMirrorArray[x];
1573  RotRightArray[x] = InternalRotRightArray[x];
1574  RotLeftArray[x] = InternalRotLeftArray[x];
1575  }
1576 }
1577 
1578 // ---------------------------------------------------------------------------
1580 {
1581 // delete TrackVectorPtr;
1582 // delete FixedTrackArrayPtr;
1583  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1584 
1585  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1586  {
1587  delete UGMIt->second;
1588  UGMIt++;
1589  }
1590  delete GapFlashGreen;
1591  delete GapFlashRed;
1592  // all the rest are cleared by the relevant automatic destructors
1593 }
1594 
1595 // ---------------------------------------------------------------------------
1596 
1598 {
1599  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1600  {
1601 // loc 0 not used, set to bmSolidBgnd
1605 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1625  };
1626 
1627  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1628  {
1629 // loc 0 not used, set to smSolidBgnd
1633 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1652  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1653  };
1654 
1655 // track types
1656  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1657  {
1658  Erase, // 1 0
1659  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1660  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1661  Crossover, Crossover, // 2 15-16
1662  Unused, // 17 (was for text in earlier development) //1 17
1665  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1669  Platform, Platform, Platform, Platform, // 4 76-79
1672  Concourse, // 1 96
1675  Simple, Simple, Simple, Simple, // 4 125-128
1676  FootCrossing, FootCrossing, // 2 129-130
1677  NamedNonStationLocation, // 1 131
1678  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1679  Simple, Simple, Simple, Simple, // 4 140-143
1680  LevelCrossing, // 1 144
1681  FootCrossing, FootCrossing // 2 145 & 146
1682  };
1683 
1684 // links
1685  int Links[FirstUnusedSpeedTagNumber][4] =
1686  {{-1, -1, -1, -1}, // erase element
1687  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1688  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1689 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1690  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1691  {-1, -1, -1, -1}, // unused
1692  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1693  {2, 7, -1, -1}, // simple
1694  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1695 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1696 // (or right diverging if no straight)
1697  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1698  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1699  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1700  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1701  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1702  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1703  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1704  {-1, -1, -1, -1}, // Concourse
1705  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1707  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1708  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1709  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1710  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1711  {-1, -1, -1, -1}, // NamedNonStationLocation
1712  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1713 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1714  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1715  {-1, -1, -1, -1}, // level crossing
1716  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1717  };
1718 
1720  {{NotSet, NotSet, NotSet, NotSet}, // unused
1724  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1726  {NotSet, NotSet, NotSet, NotSet}, // unused
1730  {Connection, Connection, NotSet, NotSet}, // simple
1734  {Lead, Trail, Lead, Trail}, // points
1736  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1744  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1750  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1759  {Connection, Connection, NotSet, NotSet}, // Arrows
1761  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1763  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1765  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1766  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1767  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1768  };
1769 
1770  for(int x = 0; x < 17; x++)
1771  {
1772  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1773  }
1774  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1775 // 17 was the old text value so don't want any graphics (now disused)
1776  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1777  {
1778  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1779  }
1780 }
1781 
1782 // ---------------------------------------------------------------------------
1783 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1784  ExistingGraphicLoaded(false), Width(16), Height(16)
1785 {
1786  OriginalGraphic = new Graphics::TBitmap;
1787  OriginalGraphic->PixelFormat = pf8bit;
1788  OriginalGraphic->Width = Width;
1789  OriginalGraphic->Height = Height;
1790  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1791 }
1792 
1793 // ---------------------------------------------------------------------------
1794 
1795 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1796  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1797 {
1798  OriginalGraphic = new Graphics::TBitmap;
1799  OriginalGraphic->PixelFormat = pf8bit;
1800  OriginalGraphic->Width = Width;
1801  OriginalGraphic->Height = Height;
1802  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1803 }
1804 
1805 // ---------------------------------------------------------------------------
1806 
1808 {
1809  delete OriginalGraphic;
1810 }
1811 
1812 // ---------------------------------------------------------------------------
1813 
1814 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1815 {
1816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1817  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1818  VPos = VPosIn;
1819  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1820 
1821  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1822  SourceRect.init(Left, Top, Left + Width, Top + Height);
1823  ScreenSourceSet = true;
1824  Utilities->CallLogPop(422);
1825 }
1826 
1827 // ---------------------------------------------------------------------------
1828 
1830 {
1831  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1832  if(!OverlayLoaded)
1833  {
1834  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1835  }
1836  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1837  {
1838  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1839  }
1840  if(!ScreenSourceSet)
1841  {
1842  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1843  }
1844  if(ExistingGraphicLoaded) // can only call one of the load functions
1845  {
1846  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1847  }
1848  if(OverlayPlotted) // don't load from screen if overlay plotted
1849  {
1850  Utilities->CallLogPop(775);
1851  return;
1852  }
1853  TRect DestRect(0, 0, Width, Height);
1854 
1856  OriginalLoaded = true;
1857  ScreenGraphicLoaded = true;
1858  Utilities->CallLogPop(423);
1859 }
1860 
1861 // ---------------------------------------------------------------------------
1862 
1863 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1864 /*
1865  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1866 */
1867 {
1868  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1869  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1870  if(!OverlayLoaded)
1871  {
1872  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1873  }
1874  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1875  {
1876  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1877  }
1878  if(ScreenGraphicLoaded) // can only call one of the load functions
1879  {
1880  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1881  }
1882  Width = WidthIn;
1883  Height = HeightIn;
1884  OriginalGraphic->Width = Width;
1885  OriginalGraphic->Height = Height;
1886  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1887  VPos += VOffset;
1888  TRect DestRect(0, 0, Width, Height);
1889 
1890  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1891  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1892  OriginalLoaded = true;
1893  ExistingGraphicLoaded = true;
1894  Utilities->CallLogPop(424);
1895 }
1896 
1897 // ---------------------------------------------------------------------------
1898 
1899 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1900 {
1901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1902  OverlayGraphic = Overlay;
1903  OverlayLoaded = true;
1904  Utilities->CallLogPop(425);
1905 }
1906 
1907 // ---------------------------------------------------------------------------
1908 
1910 {
1911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1912  if(!OverlayLoaded)
1913  {
1914  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1915  }
1916  if(!OverlayPlotted)
1917  {
1918  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1919  Disp->Update();
1920  OverlayPlotted = true;
1921  }
1922  Utilities->CallLogPop(426);
1923 }
1924 
1925 // ---------------------------------------------------------------------------
1926 
1928 {
1929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1930  if(OverlayPlotted)
1931  {
1932  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1933  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1934  {
1935  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1936  }
1937  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1938  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1939  OverlayPlotted = false;
1940  }
1941  Utilities->CallLogPop(427);
1942 }
1943 
1944 // ---------------------------------------------------------------------------
1945 
1947 {
1948  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1949  bool TrackPresent = false;
1950 
1951  if(InactiveTrackVector.size() != 0)
1952  {
1953  Utilities->CallLogPop(1333);
1954  return(false);
1955  }
1956  else if(TrackVector.size() == 0)
1957  {
1958  Utilities->CallLogPop(1334);
1959  return(true);
1960  }
1961  else
1962  {
1963  for(unsigned int x = 0; x < TrackVector.size(); x++)
1964  {
1965  if((TrackElementAt(1042, x).SpeedTag != 0))
1966  {
1967  TrackPresent = true;
1968  }
1969  }
1970  }
1971  Utilities->CallLogPop(1335);
1972  return(!TrackPresent);
1973 }
1974 
1975 // ---------------------------------------------------------------------------
1976 
1977 bool TTrack::NoActiveTrack(int Caller)
1978 {
1979  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1980  bool TrackPresent = false;
1981 
1982  if(TrackVector.size() == 0)
1983  {
1984  Utilities->CallLogPop(1582);
1985  return(true);
1986  }
1987  else
1988  {
1989  for(unsigned int x = 0; x < TrackVector.size(); x++)
1990  {
1991  if((TrackElementAt(1043, x).SpeedTag != 0))
1992  {
1993  TrackPresent = true;
1994  }
1995  break;
1996  }
1997  }
1998  Utilities->CallLogPop(1583);
1999  return(!TrackPresent);
2000 }
2001 
2002 // ---------------------------------------------------------------------------
2003 
2004 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2005 {
2006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2007  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2008  TrackEraseSuccessfulFlag = false;
2009 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
2010 // since have to match platforms as well as track
2011 // used to set TrackFinished to false if an element erased
2012 
2013  ErasedTrackVectorPosition = -1; // marker for no element erased
2014  AnsiString SName = "", ErrorString;
2016  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2017  TTrackMapIterator TrackMapPtr;
2018  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2019 
2020  if(TrackVector.size() != 0)
2021  {
2022  TrackMapKeyPair.first = HLocInput;
2023  TrackMapKeyPair.second = VLocInput;
2024  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2025  if(TrackMapPtr != TrackMap.end())
2026  {
2027  bool FoundFlag;
2028  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2029  if(FoundFlag) // should find it as it's in the map
2030  {
2031  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2032  {
2033  SName = TrackElementAt(1, VecPos).LocationName;
2034  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2035  if(ErrorString != "")
2036  {
2037  throw Exception(ErrorString + " for EraseTrackElement 1");
2038  }
2039  LocationNameMultiMap.erase(SNIt);
2040  }
2041  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2042  // ensure erase vector element before map element as iterator no longer valid after a map erase
2043  TrackMap.erase(TrackMapPtr);
2044  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2045  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2047  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2048  if(SName != "")
2049  {
2050  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2051  int HPos, VPos;
2052  if(TextHandler->FindText(1, SName, HPos, VPos))
2053  {
2054  if(TextHandler->TextErase(5, HPos, VPos, SName))
2055  {
2056  ;
2057  } // condition not used
2058 
2059  }
2060  }
2061  ErasedTrackVectorPosition = VecPos;
2062  TrackEraseSuccessfulFlag = true;
2063  }
2064  }
2065  }
2066  if(InactiveTrackVector.size() != 0)
2067  {
2068  unsigned int VecPos;
2069  InactiveTrackMapKeyPair.first = HLocInput;
2070  InactiveTrackMapKeyPair.second = VLocInput;
2071  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2072  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2073  {
2074  SName = "";
2075  VecPos = InactiveTrack2MultiMapIterator->second;
2076  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2077  {
2078  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2079  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2080  if(ErrorString != "")
2081  {
2082  throw Exception(ErrorString + " for EraseTrackElement 2A");
2083  }
2084  LocationNameMultiMap.erase(SNIt);
2085  }
2086  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2087  // ensure erase vector element before map element as iterator no longer valid after a map erase
2088  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2089  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2090  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2092  TrackEraseSuccessfulFlag = true;
2093  if(SName != "")
2094  {
2095  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2096  int HPos, VPos;
2097  if(TextHandler->FindText(2, SName, HPos, VPos))
2098  {
2099  if(TextHandler->TextErase(6, HPos, VPos, SName))
2100  {
2101  ;
2102  } // condition not used
2103 
2104  }
2105  }
2106  }
2107  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2108  {
2109  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2110  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2111  {
2112  SName = "";
2113  VecPos = InactiveTrack2MultiMapIterator->second;
2114  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2115  {
2116  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2117  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2118  if(ErrorString != "")
2119  {
2120  throw Exception(ErrorString + " for EraseTrackElement 2B");
2121  }
2122  LocationNameMultiMap.erase(SNIt);
2123  }
2124  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2125  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2126  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2128  if(SName != "")
2129  {
2130  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2131  int HPos, VPos;
2132  if(TextHandler->FindText(3, SName, HPos, VPos))
2133  {
2134  if(TextHandler->TextErase(7, HPos, VPos, SName))
2135  {
2136  ;
2137  } // condition not used
2138 
2139  }
2140  }
2141  }
2142  }
2143  }
2144  if(TrackEraseSuccessfulFlag)
2145  {
2146  CalcHLocMinEtc(2);
2147  SetTrackFinished(false);
2148  }
2149  if(InternalChecks)
2150  {
2151  CheckMapAndTrack(1); // test
2152  CheckMapAndInactiveTrack(1); // test
2153  CheckLocationNameMultiMap(6); // test
2154  }
2155  Utilities->CallLogPop(428);
2156 }
2157 
2158 // ---------------------------------------------------------------------------
2159 
2160 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks, bool PerformNameSearch)
2161 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2162 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2163 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2164 // PerformNameSearch added at v2.18.0 to speed up named element additions when area selected
2165 {
2166  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2167  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2168  bool PlatAllowedFlag = false;
2169 
2170  TrackLinkingRequiredFlag = false;
2171 /*
2172  Not erase, that covered separately.
2173  First check if Current SpeedButton assigned, then check if a platform and only
2174  permit if an appropriate trackpiece already there & not a same platform there.
2175  - can't enter a platform without track first.
2176  Then for non-platforms, check if a track piece already present at location &
2177  reject if so.
2178 */
2179 
2180  TLocationNameMultiMapEntry LocationNameEntry;
2181 
2182  LocationNameEntry.first = "";
2183  if(CurrentTag == 0)
2184  {
2185  Utilities->CallLogPop(429);
2186  return; // not assigned yet
2187  }
2188  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2189 
2190  TempTrackElement.HLoc = HLocInput;
2191  TempTrackElement.VLoc = VLocInput;
2192  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2193 // new at version 0.6 - set signal aspect depending on build mode
2194 
2195  if(TempTrackElement.TrackType == SignalPost)
2196  {
2197  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2198  // pasting a SignalPost can only have values 1 to 4
2199  {
2201  {
2202  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2203  }
2205  {
2206  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2207  }
2209  {
2210  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2211  }
2212  else
2213  {
2214  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2215  }
2216  }
2217  else if(Aspect == 1)
2218  {
2219  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2220  }
2221  else if(Aspect == 2)
2222  {
2223  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2224  }
2225  else if(Aspect == 3)
2226  {
2227  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2228  }
2229  else
2230  {
2231  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2232  }
2233  }
2234  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2235  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2236  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2237  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2238 
2239  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2240  {
2242  {
2243  NonStationOrLevelCrossingPresent = true;
2244  }
2245  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2246  {
2247  NonStationOrLevelCrossingPresent = true;
2248  }
2249  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2250  {
2251  PlatformPresent = true;
2252  }
2253  // no need to check IMPair.second since if that exists it is because .first is a platform
2254  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2255  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2256  }
2257 // check platforms
2258  if(TempTrackElement.TrackType == Platform)
2259  {
2260  if(FoundFlag) // active track element already there
2261  {
2262  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2263  {
2264  ;
2265  }
2266  // same platform type already there so above keeps PlatAllowedFlag false
2267  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2268  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2269  {
2270  PlatAllowedFlag = true;
2271  }
2272  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2273  {
2274  PlatAllowedFlag = true;
2275  }
2276  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2277  {
2278  PlatAllowedFlag = true;
2279  }
2280  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2281  {
2282  PlatAllowedFlag = true;
2283  }
2284  if(PlatAllowedFlag)
2285  {
2286  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2287  TrackPush(1, TempTrackElement);
2288  if(PerformNameSearch)
2289  {
2290  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2291  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2292  // Must be called AFTER TrackPush
2293  // No need to plot the element - Clearand ... called after this function called
2294  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2295  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2296  }
2297 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2298 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2299 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2300  if(InternalChecks)
2301  {
2302  CheckMapAndInactiveTrack(5); // test
2303  CheckLocationNameMultiMap(4); // test
2304  }
2305  Utilities->CallLogPop(430);
2306  return;
2307  }
2308  } // if(FoundFlag)
2309 
2310  Utilities->CallLogPop(431);
2311  return;
2312  } // if platform
2313 
2314 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2315  if(TempTrackElement.TrackType == NamedNonStationLocation)
2316  {
2317  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2318  (!FoundFlag && !InactiveFoundFlag))
2319  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2320  {
2321  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2322  TrackPush(2, TempTrackElement);
2323  if(PerformNameSearch)
2324  {
2325  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2326  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2327  }
2328  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2329  {
2330 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2331 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2332 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2333  }
2334  if(InternalChecks)
2335  {
2336  CheckMapAndInactiveTrack(11); // test
2337  CheckLocationNameMultiMap(12); // test
2338  }
2339  Utilities->CallLogPop(432);
2340  return;
2341  }
2342  else
2343  {
2344  Utilities->CallLogPop(433);
2345  return;
2346  }
2347  }
2348 // check if a level crossing - OK if placed on a plain straight track
2349  if(TempTrackElement.TrackType == LevelCrossing)
2350  {
2351  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2352  {
2353  TrackPush(11, TempTrackElement);
2354  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2355 // no need for reference to LC element as can't be open
2356  TrackLinkingRequiredFlag = true;
2357  Utilities->CallLogPop(1907);
2358  return;
2359  }
2360  else
2361  {
2362  Utilities->CallLogPop(1906);
2363  return; // was a level crossing but can't place it for some reason
2364  }
2365  }
2366 
2367 // check if another element already there
2368  else if(FoundFlag || InactiveFoundFlag)
2369  {
2370  Utilities->CallLogPop(434);
2371  return; // something already there (active or inactive track)
2372  }
2373 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2374 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2375 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2376 // do this after pushed into vector so that can use EnterLocationName
2377 
2378  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2379  {
2380  TrackPush(3, TempTrackElement);
2381  if(PerformNameSearch)
2382  {
2383  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2384  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2385  }
2386  }
2387  else if(TempTrackElement.TrackType == Points)
2388  {
2389  TrackPush(4, TempTrackElement);
2390  bool BothPointFillets = true;
2391  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2392  }
2393  else if(TempTrackElement.TrackType == SignalPost)
2394  {
2395  TrackPush(10, TempTrackElement);
2396  PlotSignal(12, TempTrackElement, Display);
2397  }
2398  else
2399  {
2400  TrackPush(5, TempTrackElement);
2401  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2402  }
2403  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2404  {
2405  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2406  }
2407  if(InternalChecks && PerformNameSearch) //don't carry out checks if PerformNameSearch false else will fail, should be set correctly in calling function but include to be sure
2408  {
2409  CheckMapAndTrack(2); // test
2410  CheckMapAndInactiveTrack(2); // test
2411  CheckLocationNameMultiMap(5); // test
2412  }
2413  Utilities->CallLogPop(2062);
2414 }
2415 
2416 // ---------------------------------------------------------------------------
2417 
2418 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2419  bool InternalChecks)
2420 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2421 {
2422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2423  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2424  bool PlatAllowedFlag = false;
2425 
2426  TrackLinkingRequiredFlag = false;
2427  TLocationNameMultiMapEntry LocationNameEntry;
2428 
2429  LocationNameEntry.first = "";
2430  if(TempTrackElement.SpeedTag == 0)
2431  {
2432  Utilities->CallLogPop(2063);
2433  return; // not assigned yet
2434  }
2435  TempTrackElement.HLoc = HLocInput;
2436  TempTrackElement.VLoc = VLocInput;
2437  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2438  for(int x = 0; x < 4; x++) // unset any gaps,
2439  {
2440  if(TempTrackElement.Config[x] == Gap)
2441  {
2442  TempTrackElement.ConnLinkPos[x] = -1;
2443  }
2444  TempTrackElement.Conn[x] = -1;
2445  }
2446  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2447 // new at version 0.6 - set signal aspect depending on build mode
2448  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2449 
2450  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2451  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2452  // for the active track element because these aren't set
2453  // if don't do this then get a mismatch error during map checks later
2454 
2455  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2456 
2457  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2458  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2459 
2460  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2461  {
2462  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2463  {
2464  NonStationOrLevelCrossingPresent = true;
2465  }
2466  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2467  {
2468  NonStationOrLevelCrossingPresent = true;
2469  }
2470  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2471  {
2472  PlatformPresent = true;
2473  }
2474  // no need to check IMPair.second since if that exists it is because .first is a platform
2475  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2476  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2477  }
2478 // check platforms
2479  if(TempTrackElement.TrackType == Platform)
2480  {
2481  if(FoundFlag) // active track element already there
2482  {
2483  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2484  {
2485  ;
2486  }
2487  // same platform type already there so above keeps PlatAllowedFlag false
2488  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2489  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2490  {
2491  PlatAllowedFlag = true;
2492  }
2493  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2494  {
2495  PlatAllowedFlag = true;
2496  }
2497  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2498  {
2499  PlatAllowedFlag = true;
2500  }
2501  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2502  {
2503  PlatAllowedFlag = true;
2504  }
2505  if(PlatAllowedFlag)
2506  {
2507  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2508  TrackPush(12, TempTrackElement);
2509 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2510  {
2511  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2512  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2513  }
2514  // Must be called AFTER TrackPush
2515 // No need to plot the element - Clearand ... called after this function called
2516  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2517  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2518 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2519 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2520 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2521  if(InternalChecks)
2522  {
2523  CheckMapAndInactiveTrack(12); // test
2524  CheckLocationNameMultiMap(20); // test
2525  }
2526  Utilities->CallLogPop(2064);
2527  return;
2528  }
2529  } // if(FoundFlag)
2530 
2531  Utilities->CallLogPop(2065);
2532  return;
2533  } // if platform
2534 
2535 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2536  if(TempTrackElement.TrackType == NamedNonStationLocation)
2537  {
2538  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2539  (!FoundFlag && !InactiveFoundFlag))
2540  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2541  {
2542  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2543  TrackPush(13, TempTrackElement);
2544 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2545  {
2546  {
2547  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2548  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2549  }
2550  }
2551  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2552  {
2553 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2554 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2555 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2556  }
2557  if(InternalChecks)
2558  {
2559  CheckMapAndInactiveTrack(13); // test
2560  CheckLocationNameMultiMap(21); // test
2561  }
2562  Utilities->CallLogPop(2066);
2563  return;
2564  }
2565  else
2566  {
2567  Utilities->CallLogPop(2067);
2568  return;
2569  }
2570  }
2571 // check if a level crossing - OK if placed on a plain straight track
2572  if(TempTrackElement.TrackType == LevelCrossing)
2573  {
2574  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2575  {
2576  TrackPush(14, TempTrackElement);
2577  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2578 // no need for reference to LC element as can't be open
2579  TrackLinkingRequiredFlag = true;
2580  Utilities->CallLogPop(2068);
2581  return;
2582  }
2583  else
2584  {
2585  Utilities->CallLogPop(2069);
2586  return; // was a level crossing but can't place it for some reason
2587  }
2588  }
2589 
2590 // check if another element already there
2591  else if(FoundFlag || InactiveFoundFlag)
2592  {
2593  Utilities->CallLogPop(2070);
2594  return; // something already there (active or inactive track)
2595  }
2596 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2597 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2598 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2599 // do this after pushed into vector so that can use EnterLocationName
2600 
2601  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2602  {
2603  TrackPush(15, TempTrackElement);
2604  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2605  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2606  }
2607  else if(TempTrackElement.TrackType == Points)
2608  {
2609  TrackPush(16, TempTrackElement);
2610  bool BothPointFillets = true;
2611  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2612  }
2613  else if(TempTrackElement.TrackType == SignalPost)
2614  {
2615  TrackPush(17, TempTrackElement);
2616  PlotSignal(14, TempTrackElement, Display);
2617  }
2618  else
2619  {
2620  TrackPush(18, TempTrackElement);
2621  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2622  }
2623  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2624  {
2625  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2626  }
2627  if(InternalChecks)
2628  {
2629  CheckMapAndTrack(12); // test
2630  CheckMapAndInactiveTrack(14); // test
2631  CheckLocationNameMultiMap(22); // test
2632  }
2633  Utilities->CallLogPop(2071);
2634 }
2635 
2636 // ---------------------------------------------------------------------------
2637 
2638 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2639 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2640 // return bool = true for success
2641 // LocError = true for location error & HLoc & VLoc to be inverted
2642 {
2643  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2644  LocError = false;
2645  SetTrackFinished(false);
2646  if(TrackVector.size() == 0)
2647  {
2648  Utilities->CallLogPop(437);
2649  return(false);
2650  }
2651  if(GapsUnset(7))
2652  {
2653  if(GiveMessages)
2654  {
2655  ShowMessage("Gaps must be set before track can be validated");
2656  }
2657  Utilities->CallLogPop(1135);
2658  return(false);
2659  }
2660 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2661 // returns true for any unset gaps
2663  {
2664  // can keep this exception as protected by the GapsUnset call above
2665  throw Exception("Error, gaps unset when TryToConnectTrack called");
2666  }
2668  CheckGapMap(1); // test
2669 // Gap connections now securely defined
2670 
2671  CheckMapAndTrack(8); // test
2672 
2673 // Perform a pre-check prior to TrackMap being compiled
2674  if(GiveMessages)
2675  {
2676  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2677  {
2678  Utilities->CallLogPop(439);
2679  return(false);
2680  }
2681  }
2682  else
2683  {
2684  if(!LinkTrackNoMessages(1, false))
2685  {
2686  Utilities->CallLogPop(1131);
2687  return(false);
2688  }
2689  }
2690 // here if pre-check successful
2691  if(!RepositionAndMapTrack(0))
2692  {
2693  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2694  Utilities->CallLogPop(1138);
2695  return(false);
2696  }
2697 // now perform the final assembly - FinalCall = true
2698  if(GiveMessages)
2699  {
2700  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2701  {
2702  Utilities->CallLogPop(1116);
2703  return(false);
2704  }
2705  }
2706  else
2707  {
2708  if(!LinkTrackNoMessages(2, true))
2709  {
2710  Utilities->CallLogPop(1132);
2711  return(false);
2712  }
2713  }
2714 // success
2715 
2716  PopulateLCVector(0);
2717  CheckGapMap(2); // test
2718  CheckMapAndTrack(3); // test
2719  CheckMapAndInactiveTrack(3); // test
2720  CheckLocationNameMultiMap(9); // test
2721  SetTrackFinished(true);
2722 
2723 // Build ContinuationNameMap
2724  std::pair<AnsiString, char>TempMapPair;
2725 
2726  ContinuationNameMap.clear();
2727  for(int x = 0; x < Track->TrackVectorSize(); x++)
2728  {
2729  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2730  {
2731  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2732  TempMapPair.second = 'x'; // unused
2733  ContinuationNameMap.insert(TempMapPair);
2734  }
2735  }
2736 
2737 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2738 //(don't report blue areas without track as these unlikely to be mistakes)
2739 
2740  if(TrackFinished)
2741  {
2742  AnsiString Name = "";
2743  typedef std::list<AnsiString> TNoPlatsList;
2744  TNoPlatsList::iterator NPLIt;
2745  TNoPlatsList NoPlatsList;
2746  typedef std::list<AnsiString> TLocNameList;
2747  TLocNameList LocNameList; //single entry for each name
2750  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2751  {
2752  LocNameList.push_back(LNMMIt->first);
2753  }
2754  LocNameList.sort();
2755  LocNameList.unique();
2756  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2757  {
2758  Name = *LNLIt;
2759  MMRange = LocationNameMultiMap.equal_range(Name);
2760  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2761  {
2762  continue;
2763  }
2764  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2765  {
2766  if((LNMMIt->second) < 0) //active track element
2767  {
2768  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2769  {
2770  break;
2771  }
2772  }
2773  else //inactive
2774  {
2775  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2776  {
2777  break;
2778  }
2779  }
2780  TempIt = MMRange.second;
2781  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2782  {
2783  NoPlatsList.push_back(Name);
2784  }
2785  }
2786  }
2787  if(!NoPlatsList.empty())
2788  {
2789  AnsiString NoPlatsAnsiList = "";
2790  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2791  {
2792  NoPlatsAnsiList += *NPLIt + '\n';
2793  }
2794  if(!NoPlatsMessageSent)
2795  {
2796  if(NoPlatsList.size() > 1)
2797  {
2798  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2799  }
2800  else
2801  {
2802  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2803  }
2804  NoPlatsMessageSent = true;
2805  }
2806  }
2807  }
2808  Utilities->CallLogPop(440);
2809  return(true);
2810 }
2811 
2812 // ---------------------------------------------------------------------------
2813 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2814 // unused - too time-consuming - double brute force search
2815 {
2816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2817  int NewHLoc, NewVLoc;
2818  bool ConnectionFoundFlag, LinkFoundFlag;
2819 
2820  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2821  {
2822  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2823  {
2824  if(TrackElementAt(1061, x).Link[y] <= 0)
2825  {
2826  continue; // no link
2827  }
2828  if(TrackElementAt(1062, x).Config[y] == End)
2829  {
2830  continue; // buffer or continuation
2831  }
2832  if(TrackElementAt(1063, x).Config[y] == Gap)
2833  {
2834  continue; // gap jump
2835  }
2836  // get required H & V for track element joining link 'y'
2837  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2838  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2839  // find track element if present
2840  ConnectionFoundFlag = false;
2841  for(unsigned int z = 0; z < TrackVector.size(); z++)
2842  {
2843 // if(TrackElementAt(5, z).TrackType == Platform)
2844 // continue; //skip platforms
2845  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2846  {
2847  ConnectionFoundFlag = true;
2848  // find connecting link in the newly found track element if there is one
2849  LinkFoundFlag = false;
2850  for(unsigned int a = 0; a < 4; a++)
2851  {
2852  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2853  {
2854  LinkFoundFlag = true;
2855  }
2856  }
2857  // if there isn't a corresponding link set the invert values for the offending element
2858  if(!LinkFoundFlag)
2859  {
2860  HLoc = TrackElementAt(1072, x).HLoc;
2861  VLoc = TrackElementAt(1073, x).VLoc;
2862  Utilities->CallLogPop(441);
2863  return(true);
2864  }
2865  break; // success, so break out of 'z' loop
2866  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2867 
2868  } // for z...
2869  // if there isn't a connection set the invert values for the offending element
2870  if(!ConnectionFoundFlag)
2871  {
2872  HLoc = TrackElementAt(1074, x).HLoc;
2873  VLoc = TrackElementAt(1075, x).VLoc;
2874  Utilities->CallLogPop(442);
2875  return(true);
2876  }
2877  } // for y....
2878  } // for x...
2879  Utilities->CallLogPop(443);
2880  return(false); // all OK
2881 }
2882 
2883 // ---------------------------------------------------------------------------
2884 
2885 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2886 {
2887  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2888  TrackElement.LogTrack(0));
2889  bool FoundFlag;
2890 
2891  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2892  if(FoundFlag)
2893  {
2894  TrackElement = TrackElementAt(1076, Position);
2895  }
2896  Utilities->CallLogPop(444);
2897  return(FoundFlag);
2898 }
2899 
2900 // ---------------------------------------------------------------------------
2901 
2903 {
2904  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2905  if(NextTrackElementPtr >= TrackVector.end())
2906  {
2907  Utilities->CallLogPop(1336);
2908  return(false);
2909  }
2910  Next = *NextTrackElementPtr;
2912  Utilities->CallLogPop(1337);
2913  return(true);
2914 }
2915 
2916 // ---------------------------------------------------------------------------
2917 
2919 {
2920  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2922  {
2923  Utilities->CallLogPop(1338);
2924  return(false);
2925  }
2926  Next = *NextTrackElementPtr;
2928  Utilities->CallLogPop(1339);
2929  return(true);
2930 }
2931 
2932 // ---------------------------------------------------------------------------
2933 
2934 int TTrack::NumberOfGaps(int Caller)
2935 
2936 {
2937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2938  int Count = 0;
2939 
2940  if(TrackVector.size() == 0)
2941  {
2942  Utilities->CallLogPop(1340);
2943  return(0);
2944  }
2945  for(unsigned int x = 0; x < TrackVector.size(); x++)
2946  {
2947  if(TrackElementAt(1077, x).TrackType == GapJump)
2948  {
2949  Count++;
2950  }
2951  }
2952  Utilities->CallLogPop(1341);
2953  return(Count);
2954 }
2955 
2956 // ---------------------------------------------------------------------------
2958 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2959 // returns true for any unset gaps
2960 {
2961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2962  bool UnsetGaps = false;
2963 
2964  if(TrackVector.size() == 0)
2965  {
2966  Utilities->CallLogPop(445);
2967  return(false);
2968  }
2969  for(unsigned int x = 0; x < TrackVector.size(); x++)
2970  {
2971  if(TrackElementAt(1078, x).TrackType != GapJump)
2972  {
2973  for(unsigned int y = 0; y < 4; y++)
2974  {
2975  TrackElementAt(1079, x).Conn[y] = -1;
2976  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2977  }
2978  }
2979  else // GapJump
2980  {
2981 // int tempint = TrackElementAt(, x).Conn[0);
2982 
2983  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2984  {
2985  for(unsigned int y = 0; y < 4; y++)
2986  {
2987  TrackElementAt(1082, x).Conn[y] = -1;
2988  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2989  }
2990  UnsetGaps = true;
2991  continue; // to next 'x'
2992  }
2993  else // set, but may not have matching element, or that element may not be set
2994  {
2995  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2996  {
2997  TrackElementAt(1084, x).Conn[y] = -1;
2998  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2999  }
3000 
3001  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
3002  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
3003  {
3004  for(unsigned int y = 0; y < 4; y++)
3005  {
3006  TrackElementAt(1087, x).Conn[y] = -1;
3007  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
3008  }
3009  UnsetGaps = true;
3010  continue; // to next 'x'
3011  }
3012 // here if gap connection is itself a GapJump
3013  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3014  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3015  // if not clear Conns & CLks & reset Lk[0]
3016  {
3017  for(unsigned int y = 0; y < 4; y++)
3018  {
3019  TrackElementAt(1090, x).Conn[y] = -1;
3020  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3021  }
3022  UnsetGaps = true;
3023  continue; // to next 'x'
3024  }
3025 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3026 // hence no more action needed on these Conns & CLks
3027  }
3028  } // else //gap jump
3029 
3030  } // for x...
3031  Utilities->CallLogPop(446);
3032  return(UnsetGaps);
3033 }
3034 
3035 // ---------------------------------------------------------------------------
3036 
3037 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3038 {
3039 // VecFile already open and its pointer at right place on calling
3040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3041  int TempInt;
3042 
3043  TrackClear(1);
3044 // load track elements
3045  int NumberOfActiveElements = 0;
3046 
3047  GraphicsFollow = false;
3048  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3049  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3050 
3051  if(MarkerString[MarkerString.Length()] == '1')
3052  {
3053  GraphicsFollow = true;
3054  }
3055  for(int x = 0; x < NumberOfActiveElements; x++)
3056  {
3057  VecFile >> TempInt; // TrackVectorNumber, not used
3058  VecFile >> TempInt; // SpeedTag
3059  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3060  VecFile >> TempInt;
3061  TrackElement.HLoc = TempInt;
3062  VecFile >> TempInt;
3063  TrackElement.VLoc = TempInt;
3064  if(TrackElement.TrackType == GapJump)
3065  {
3066  VecFile >> TempInt;
3067  TrackElement.ConnLinkPos[0] = TempInt;
3068  VecFile >> TempInt;
3069  TrackElement.Conn[0] = TempInt;
3070  }
3071  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3072  {
3073  VecFile >> TempInt;
3074  TrackElement.Attribute = TempInt;
3075  }
3076  if(TrackElement.TrackType == SignalPost)
3077  {
3078  VecFile >> TempInt;
3079  if(TempInt == 0)
3080  {
3081  TrackElement.CallingOnSet = false;
3082  }
3083  else
3084  {
3085  TrackElement.CallingOnSet = true;
3086  }
3087  }
3088  VecFile >> TempInt;
3089  TrackElement.Length01 = TempInt;
3090  VecFile >> TempInt;
3091  TrackElement.Length23 = TempInt;
3092  VecFile >> TempInt;
3093  if((TempInt != -1) && (TempInt < 10))
3094  {
3095  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3096  }
3097  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3098  {
3099  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3100  }
3101  TrackElement.SpeedLimit01 = TempInt;
3102  VecFile >> TempInt;
3103  if((TempInt != -1) && (TempInt < 10))
3104  {
3105  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3106  }
3107  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3108  {
3109  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3110  }
3111  TrackElement.SpeedLimit23 = TempInt;
3112 
3113  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3114  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3115  SetElementID(0, TrackElement);
3116  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3117 // new for v0.6
3118  if(TrackElement.TrackType == SignalPost)
3119  {
3120  if(Marker[1] == '3')
3121  {
3122  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3123  }
3124  else if(Marker[1] == '2')
3125  {
3126  TrackElement.SigAspect = TTrackElement::TwoAspect;
3127  }
3128  else if(Marker[1] == 'G')
3129  {
3130  TrackElement.SigAspect = TTrackElement::GroundSignal;
3131  }
3132  else
3133  {
3134  TrackElement.SigAspect = TTrackElement::FourAspect;
3135  }
3136  }
3137  if(TrackElement.SpeedTag != 0)
3138  {
3139  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3140  }
3141  }
3142  int NumberOfInactiveElements = 0;
3143 
3144  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3145  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3146  for(int x = 0; x < NumberOfInactiveElements; x++)
3147  {
3148  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3149  VecFile >> TempInt; // SpeedTag
3150  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3151  VecFile >> TempInt;
3152  TrackElement.HLoc = TempInt;
3153  VecFile >> TempInt;
3154  TrackElement.VLoc = TempInt;
3155  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3156  SetElementID(3, TrackElement);
3157  TrackPush(9, TrackElement);
3158  Utilities->LoadFileString(VecFile); // marker
3159  }
3160  bool LocError = false; // needed for TryToConnectTrack but not used
3161  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3162 
3163  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3164  {
3165  SetTrackFinished(true);
3166  }
3167  else
3168  {
3169  SetTrackFinished(false);
3170  }
3171 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3172 // CheckMapAndInactiveTrack(8);
3173 // CheckLocationNameMultiMap(10);
3174  Utilities->CallLogPop(448);
3175 }
3176 
3177 // ---------------------------------------------------------------------------
3178 
3179 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3180 {
3181 // VecFile already open and its pointer at right place on calling
3182  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3183 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3184 // & load into UserGraphicItem then store in UserGraphicVector
3185  UserGraphicVector.clear();
3186  TUserGraphicItem UGI;
3187  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3188 
3189  for(int x = 0; x < NumberOfGraphics; x++)
3190  {
3191  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3192  UGI.HPos = Utilities->LoadFileInt(VecFile);
3193  UGI.VPos = Utilities->LoadFileInt(VecFile);
3194  UGI.Width = 0; // provisional value
3195  UGI.Height = 0; // provisional value
3196  UGI.UserGraphic = NULL; // provisional value
3197  UserGraphicVector.push_back(UGI);
3198  }
3199 // now load the map & set Width, Height & TPicture*
3200  bool FileError = false;
3201 
3202  for(int x = 0; x < NumberOfGraphics; x++)
3203  {
3204  if(FileError)
3205  {
3206  break; // otherwise keeps going round the loop
3207  }
3208  UGI = UserGraphicVectorAt(0, x);
3209  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3210  {
3211  try
3212  {
3213 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3214  UGME.first = UGI.FileName;
3215  UGME.second = new TPicture;
3216  UGME.second->LoadFromFile(UGME.first); // errors caught below
3217  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3218  {
3219  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3220  }
3221  UGI.UserGraphic = UGME.second;
3222  UGI.Width = UGI.UserGraphic->Width;
3223  UGI.Height = UGI.UserGraphic->Height;
3224  UserGraphicVectorAt(1, x) = UGI;
3225  }
3226  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3227  {
3228  //message already sent in CheckUserGraphics
3229  FileError = true;
3230  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3231  if(!UserGraphicMap.empty())
3232  {
3233  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3234  {
3235  delete UGMIt->second;
3236  }
3237  UserGraphicMap.clear();
3238  }
3239  }
3240  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3241  {
3242  //message already sent in CheckUserGraphics
3243  FileError = true;
3244  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3245  if(!UserGraphicMap.empty())
3246  {
3247  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3248  {
3249  delete UGMIt->second;
3250  }
3251  UserGraphicMap.clear();
3252  }
3253  }
3254  }
3255  else
3256  {
3257  bool FoundInMap = false;
3258  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3259  {
3260  if(UGI.FileName == UGMIt->first) // already exists in map
3261  {
3262  UGI.UserGraphic = UGMIt->second;
3263  UGI.Width = UGI.UserGraphic->Width;
3264  UGI.Height = UGI.UserGraphic->Height;
3265  UserGraphicVectorAt(2, x) = UGI;
3266  FoundInMap = true;
3267  break;
3268  }
3269  }
3270  if(!FoundInMap)
3271  {
3272  try
3273  {
3275  UGME.first = UGI.FileName;
3276  UGME.second = new TPicture;
3277  UGME.second->LoadFromFile(UGME.first); // errors caught below
3278  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3279  {
3280  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3281  }
3282  UGI.UserGraphic = UGME.second;
3283  UGI.Width = UGI.UserGraphic->Width;
3284  UGI.Height = UGI.UserGraphic->Height;
3285  UserGraphicVectorAt(3, x) = UGI;
3286  }
3287  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3288  {
3289  //message already sent in CheckUserGraphics
3290  FileError = true;
3291  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3292  if(!UserGraphicMap.empty())
3293  {
3294  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3295  {
3296  delete UGMIt->second;
3297  }
3298  UserGraphicMap.clear();
3299  }
3300  }
3301  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3302  {
3303  //message already sent in CheckUserGraphics
3304  FileError = true;
3305  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3306  if(!UserGraphicMap.empty())
3307  {
3308  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3309  {
3310  delete UGMIt->second;
3311  }
3312  UserGraphicMap.clear();
3313  }
3314  }
3315  }
3316  }
3317  }
3318  Utilities->CallLogPop(2167);
3319 }
3320 
3321 // ---------------------------------------------------------------------------
3322 
3323 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3324 {
3325 // VecFile already open and its pointer at right place on calling
3326 // if GraphicsFollow true, then save Marker as **Active elements**1
3327 // save trackfinished flag
3328  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3329  TTrackElement TrackElement, InactiveTrackElement;
3330 
3331 // save track elements
3332  Utilities->SaveFileInt(VecFile, TrackVector.size());
3333  if(GraphicsFollow)
3334  {
3335  VecFile << "**Active elements**1" << '\0' << '\n';
3336  }
3337  else
3338  {
3339  VecFile << "**Active elements**" << '\0' << '\n';
3340  }
3341  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3342  {
3343  TrackElement = TrackElementAt(1092, x);
3344  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3345  VecFile << TrackElement.SpeedTag << '\n';
3346  VecFile << TrackElement.HLoc << '\n';
3347  VecFile << TrackElement.VLoc << '\n';
3348  if(TrackElement.TrackType == GapJump)
3349  {
3350  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3351  VecFile << TrackElement.Conn[0] << '\n';
3352  }
3353  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3354  {
3355  VecFile << TrackElement.Attribute << '\n';
3356  }
3357  if(TrackElement.TrackType == SignalPost)
3358  {
3359  if(TrackElement.CallingOnSet)
3360  {
3361  VecFile << int(1) << '\n';
3362  }
3363  else
3364  {
3365  VecFile << int(0) << '\n';
3366  }
3367  }
3368  VecFile << TrackElement.Length01 << '\n';
3369  VecFile << TrackElement.Length23 << '\n';
3370  VecFile << TrackElement.SpeedLimit01 << '\n';
3371  VecFile << TrackElement.SpeedLimit23 << '\n';
3372  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3373  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3374 // new for v0.6
3375  if(TrackElement.TrackType == SignalPost)
3376  {
3377  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3378  {
3379  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3380  }
3381  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3382  {
3383  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3384  }
3385  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3386  {
3387  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3388  }
3389  else // 4 aspect
3390  {
3391  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3392  }
3393  }
3394  else
3395  {
3396  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3397  }
3398  }
3399 
3400  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3401  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3402  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3403  {
3404  InactiveTrackElement = InactiveTrackElementAt(136, x);
3405  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3406  VecFile << InactiveTrackElement.SpeedTag << '\n';
3407  VecFile << InactiveTrackElement.HLoc << '\n';
3408  VecFile << InactiveTrackElement.VLoc << '\n';
3409  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3410  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3411  }
3412  Utilities->CallLogPop(449);
3413 }
3414 
3415 // ---------------------------------------------------------------------------
3416 
3417 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3418 {
3419 // VecFile already open and its pointer at right place on calling
3420 // check trackfinished flag
3421 // inactive elements follow immediately after active elements, no need to check for a marker between them
3422  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3423  int TempInt;
3424 
3425  GraphicsFollow = false;
3426  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3427  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3428  {
3429  Utilities->CallLogPop(1513);
3430  return(false);
3431  }
3432 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3433  AnsiString MarkerString;
3434 
3435  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3436  {
3437  Utilities->CallLogPop(1758);
3438  return(false);
3439  }
3440  if(MarkerString[MarkerString.Length()] == '1')
3441  {
3442  GraphicsFollow = true;
3443  }
3444  for(int x = 0; x < NumberOfActiveElements; x++)
3445  {
3446  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3447  {
3448  Utilities->CallLogPop(1759);
3449  return(false);
3450  }
3451  VecFile >> TempInt;
3452  int SpeedTag = TempInt;
3453  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3454  {
3455  Utilities->CallLogPop(1514);
3456  return(false);
3457  }
3458  VecFile >> TempInt;
3459  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3460  {
3461  Utilities->CallLogPop(1495);
3462  return(false);
3463  }
3464  VecFile >> TempInt;
3465  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3466  {
3467  Utilities->CallLogPop(1497);
3468  return(false);
3469  }
3470  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3471  {
3472  VecFile >> TempInt;
3473  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3474  {
3475  Utilities->CallLogPop(1499);
3476  return(false);
3477  }
3478  VecFile >> TempInt;
3479  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3480  {
3481  Utilities->CallLogPop(1500);
3482  return(false);
3483  }
3484  }
3485  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3486  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3487  {
3488  VecFile >> TempInt;
3489  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3490  {
3491  Utilities->CallLogPop(1502);
3492  return(false);
3493  }
3494  }
3495  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3496  {
3497  VecFile >> TempInt;
3498  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3499  {
3500  Utilities->CallLogPop(1155);
3501  return(false);
3502  }
3503  }
3504  VecFile >> TempInt;
3505  if((TempInt < -1) || (TempInt > 999999)) // Length01
3506  {
3507  Utilities->CallLogPop(1503);
3508  return(false);
3509  }
3510  VecFile >> TempInt;
3511  if((TempInt < -1) || (TempInt > 999999)) // Length23
3512  {
3513  Utilities->CallLogPop(1504);
3514  return(false);
3515  }
3516  VecFile >> TempInt;
3517  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3518  {
3519  Utilities->CallLogPop(1505);
3520  return(false);
3521  }
3522  VecFile >> TempInt;
3523  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3524  {
3525  Utilities->CallLogPop(1506);
3526  return(false);
3527  }
3528  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3529  {
3530  Utilities->CallLogPop(1142);
3531  return(false); // LocationName
3532  }
3533  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3534  {
3535  Utilities->CallLogPop(1143);
3536  return(false); // ActiveTrackElementName
3537  }
3538  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3539  {
3540  Utilities->CallLogPop(1787);
3541  return(false); // marker
3542  }
3543  }
3544  int NumberOfInactiveElements = 0;
3545 
3546  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3547  if(NumberOfInactiveElements < 0) // No of active elements
3548  {
3549  Utilities->CallLogPop(1493);
3550  return(false);
3551  }
3552  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3553  {
3554  Utilities->CallLogPop(1764);
3555  return(false); // **Inactive elements** marker
3556  }
3557  for(int x = 0; x < NumberOfInactiveElements; x++)
3558  {
3559  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3560  {
3561  Utilities->CallLogPop(1765);
3562  return(false);
3563  }
3564  VecFile >> TempInt;
3565  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3566  {
3567  Utilities->CallLogPop(1494);
3568  return(false);
3569  }
3570  VecFile >> TempInt;
3571  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3572  {
3573  Utilities->CallLogPop(1496);
3574  return(false);
3575  }
3576  VecFile >> TempInt;
3577  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3578  {
3579  Utilities->CallLogPop(1498);
3580  return(false);
3581  }
3582  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3583  {
3584  Utilities->CallLogPop(1144);
3585  return(false); // LocationName
3586  }
3587  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3588  {
3589  Utilities->CallLogPop(1788);
3590  return(false); // marker
3591  }
3592  }
3593  Utilities->CallLogPop(1507);
3594  return(true);
3595 }
3596 
3597 // ---------------------------------------------------------------------------
3598 
3599 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3600 {
3601  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3602  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3603 
3604  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3605  {
3606  Utilities->CallLogPop(2168);
3607  return(false);
3608  }
3609  // filename in Graphics folder, then HPos, then VPos
3610  AnsiString FileName = "", TempStr = "";
3611 
3612  for(int x = 0; x < NumberOfGraphics; x++)
3613  {
3614  TPicture *TempPicture = new TPicture;
3615  try
3616  {
3617  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3618  {
3619  Utilities->CallLogPop(2169);
3620  delete TempPicture;
3621  return(false);
3622  }
3623  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3624  delete TempPicture;
3625  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3626  {
3627  Utilities->CallLogPop(2170);
3628  return(false);
3629  }
3630  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3631  {
3632  Utilities->CallLogPop(2171);
3633  return(false);
3634  }
3635  }
3636  catch(const EInvalidGraphic &e) //non error catch
3637  {
3638  //move file pointer to end of graphic section for later checks in session files
3639  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3640  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3641  for(int y = x + 1; y < NumberOfGraphics; y++)
3642  {
3643  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3644  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3645  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3646  }
3647  ShowMessage(FileName +
3648  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3649  Utilities->CallLogPop(2172);
3650  delete TempPicture;
3651  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3652  }
3653  catch(const Exception &e) //non error catch
3654  {
3655  //move file pointer to end of graphic section for later checks in session files
3656  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3657  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3658  for(int y = x + 1; y < NumberOfGraphics; y++)
3659  {
3660  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3661  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3662  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3663  }
3664  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3665  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3666  Utilities->CallLogPop(2173);
3667  delete TempPicture;
3668  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3669  }
3670  }
3671  Utilities->CallLogPop(2174);
3672  return(true);
3673 }
3674 
3675 // ---------------------------------------------------------------------------
3676 
3677 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3678 {
3679  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3680  int VecSize = Track->BarriersDownVector.size();
3681 
3682  Utilities->SaveFileInt(OutFile, VecSize);
3683  for(int x = 0; x < VecSize; x++)
3684  {
3686  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3687  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3688  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3689  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3690  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3691  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3692  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3693  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3694  }
3695  Utilities->CallLogPop(1963);
3696 }
3697 
3698 // ---------------------------------------------------------------------------
3699 
3700 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3701 {
3702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3703  int VecSize = Track->ChangingLCVector.size();
3704 
3705  Utilities->SaveFileInt(OutFile, VecSize);
3706  for(int x = 0; x < VecSize; x++)
3707  {
3709  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3710  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3711  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3712  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3713  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3714  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3715  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3716  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3717  }
3718  Utilities->CallLogPop(1980);
3719 }
3720 
3721 // ---------------------------------------------------------------------------
3722 
3723 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3724 {
3725  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3726  int VecSize = Utilities->LoadFileInt(VecFile);
3727 
3728  for(int x = 0; x < VecSize; x++)
3729  {
3730  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3731  {
3732  Utilities->CallLogPop(1970);
3733  return(false);
3734  }
3735  if(!Utilities->CheckFileBool(VecFile))
3736  {
3737  Utilities->CallLogPop(1971);
3738  return(false);
3739  }
3740  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3741  {
3742  Utilities->CallLogPop(1972);
3743  return(false);
3744  }
3745  if(!Utilities->CheckFileDouble(VecFile))
3746  {
3747  Utilities->CallLogPop(1973);
3748  return(false);
3749  }
3750  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3751  {
3752  Utilities->CallLogPop(1974);
3753  return(false);
3754  }
3755  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3756  {
3757  Utilities->CallLogPop(1975);
3758  return(false);
3759  }
3760  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3761  {
3762  Utilities->CallLogPop(1976);
3763  return(false);
3764  }
3765  if(!Utilities->CheckFileDouble(VecFile))
3766  {
3767  Utilities->CallLogPop(1977);
3768  return(false);
3769  }
3770  }
3771  Utilities->CallLogPop(1978);
3772  return(true);
3773 }
3774 
3775 // ---------------------------------------------------------------------------
3776 
3777 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3778 {
3779  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3780  int VecSize = Utilities->LoadFileInt(VecFile);
3781 
3782  for(int x = 0; x < VecSize; x++)
3783  {
3784  TActiveLevelCrossing TALC;
3785  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3786  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3787  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3788  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3789  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3790  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3791  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3792  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3793  BarriersDownVector.push_back(TALC);
3794  }
3795  Utilities->CallLogPop(1979);
3796 }
3797 
3798 // ---------------------------------------------------------------------------
3799 
3800 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3801 /*
3802  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3803  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3804  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3805 */
3806 {
3807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3808  TTrackElement Next;
3809 
3810 // Disp->ClearDisplay();
3812  while(ReturnNextInactiveTrackElement(0, Next))
3813  {
3814  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3815  {
3816  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3817  {
3818  // only plot if on screen, to save time
3819  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3821  {
3822  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3823  }
3824  }
3825  }
3826  }
3827 
3828  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3829 
3830  NextTrackElementPtr = TrackVector.begin();
3831  while(ReturnNextTrackElement(0, Next))
3832  {
3833  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3834  {
3835  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3837  {
3838  if(Next.TrackType == Points)
3839  {
3840  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3841  }
3842  else if(Next.TrackType == SignalPost)
3843  {
3844  PlotSignal(9, Next, Disp);
3845  }
3846  else if(Next.TrackType == GapJump)
3847  {
3848  PlotGap(0, Next, Disp);
3849  }
3850  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3851  {
3852  PlotContinuation(0, Next, Disp);
3853  }
3854  else
3855  {
3856  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3857  }
3858  }
3859  }
3860  }
3861 
3862  if(BothPointFilletsAndBasicLCs)
3863  {
3865  while(ReturnNextInactiveTrackElement(4, Next))
3866  {
3867  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3868  {
3869  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3870  {
3871  // only plot if on screen, to save time, & OK as plotting one by one here
3872  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3874  {
3875  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3876  {
3877  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3878  }
3879  else
3880  {
3881  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3882  }
3883  }
3884  }
3885  }
3886  }
3887  }
3888  Disp->Update();
3889  Utilities->CallLogPop(468);
3890 }
3891 
3892 // ---------------------------------------------------------------------------
3893 
3894 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3895 {
3896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3897  if(UserGraphicVector.empty())
3898  {
3899  Utilities->CallLogPop(2175);
3900  return;
3901  }
3902  TUserGraphicItem UGI;
3903 
3904  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3905  {
3906  UGI = UserGraphicVectorAt(4, x);
3907  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3908  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3909  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3910  {
3911  Disp->PlotAndAddUserGraphic(0, UGI);
3912  }
3913  }
3914  Disp->Update();
3915  Utilities->CallLogPop(2176);
3916 }
3917 
3918 // ---------------------------------------------------------------------------
3919 
3920 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3921 /*
3922  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3923 */
3924 {
3925  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3926 // need to change graphics back to black on white if have a dark background
3927  TColor OldTransparentColour = Utilities->clTransparent;
3928 
3930  {
3931  Utilities->clTransparent = TColor(0xFFFFFF); // white
3934  }
3935  TTrackElement Next;
3936 
3937  Bitmap->Canvas->CopyMode = cmSrcCopy;
3939  Graphics::TBitmap *GraphicOutput;
3940 
3941  while(ReturnNextInactiveTrackElement(2, Next))
3942  {
3943  GraphicOutput = Next.GraphicPtr;
3944  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3945  {
3946  if(Next.LocationName == "") // plot as named or unnamed (striped)
3947  {
3948  // default is not striped
3949  switch(Next.SpeedTag)
3950  {
3951  case 76: // t platform
3952  GraphicOutput = RailGraphics->gl76Striped;
3953  break;
3954 
3955  case 77: // h platform
3956  GraphicOutput = RailGraphics->bm77Striped;
3957  break;
3958 
3959  case 78: // v platform
3960  GraphicOutput = RailGraphics->bm78Striped;
3961  break;
3962 
3963  case 79: // r platform
3964  GraphicOutput = RailGraphics->gl79Striped;
3965  break;
3966 
3967  case 96: // concourse
3968  GraphicOutput = RailGraphics->ConcourseStriped;
3969  break;
3970 
3971  case 129: // v footbridge
3972  GraphicOutput = RailGraphics->gl129Striped;
3973  break;
3974 
3975  case 130: // h footbridge
3976  GraphicOutput = RailGraphics->gl130Striped;
3977  break;
3978 
3979  case 131: // non-station named loc
3980  GraphicOutput = RailGraphics->bmNameStriped;
3981  break;
3982 
3983  case 145: // v underpass
3984  GraphicOutput = RailGraphics->gl145Striped;
3985  break;
3986 
3987  case 146: // h underpass
3988  GraphicOutput = RailGraphics->gl146Striped;
3989  break;
3990 
3991  default:
3992  GraphicOutput = Next.GraphicPtr;
3993  break;
3994  }
3995  }
3996  if(Next.SpeedTag == 144) // level crossing
3997  {
3998  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3999  {
4000  GraphicOutput = RailGraphics->LCBothVer;
4001  }
4002  else
4003  {
4004  GraphicOutput = RailGraphics->LCBothHor;
4005  }
4006  }
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4008  }
4009  }
4010 
4011  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
4012 
4013 
4014  NextTrackElementPtr = TrackVector.begin();
4015  while(ReturnNextTrackElement(2, Next))
4016  {
4017  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4018  {
4019  if(Next.TrackType == Points) // plot both fillets
4020  {
4021  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4022  if(Next.SpeedTag < 28)
4023  {
4024  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4026  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4028  }
4029  else if(Next.SpeedTag < 132)
4030  {
4031  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4032  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4033  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4034  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4035  }
4036  else
4037  {
4038  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4039  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4040  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4041  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4042  }
4043  }
4044  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4045  {
4046  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4047  {
4048  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4049  }
4050  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4051  {
4052  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4053  }
4054  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4055  {
4056  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4057  }
4058  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4059  {
4060  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4061  }
4062  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4063  {
4064  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4065  }
4066  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4067  {
4068  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4069  }
4070  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4071  {
4072  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4073  }
4074  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4075  {
4076  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4077  }
4078  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4079  {
4080  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4081  }
4082  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4083  {
4084  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4085  }
4086  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4087  {
4088  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4089  }
4090  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4091  {
4092  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4093  }
4094  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4095  {
4096  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4097  }
4098  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4099  {
4100  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4101  }
4102  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4103  {
4104  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4105  }
4106  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4107  {
4108  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4109  }
4110  }
4111  // below added for version 0.6, only stop signals to be drawn
4112  else if(Next.TrackType == SignalPost)
4113  {
4114  for(int x = 0; x < 40; x++)
4115  {
4116  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4117  {
4118  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4119  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4120  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4121  int HOffset = 0;
4122  if(Next.SpeedTag > 73)
4123  {
4124  HOffset = 5;
4125  }
4126  else if(Next.SpeedTag == 71)
4127  {
4128  HOffset = 9;
4129  }
4130  int VOffset = 0;
4131  if(Next.SpeedTag == 69)
4132  {
4133  VOffset = 9;
4134  }
4135  else if(Next.SpeedTag == 72)
4136  {
4137  VOffset = 5;
4138  }
4139  else if(Next.SpeedTag == 74)
4140  {
4141  VOffset = 5;
4142  }
4143  Graphics::TBitmap *GraphicPtr;
4144  if(Next.SpeedTag > 71)
4145  {
4146  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4147  }
4148  else if(Next.SpeedTag < 70)
4149  {
4150  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4151  }
4152  else
4153  {
4154  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4155  }
4156  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4157  // plot special signal platform if present
4158  Graphics::TBitmap* SignalPlatformGraphic;
4159  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4160  {
4161  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4162  }
4163  // now plot signal (double yellow overwrites most of signal platform if present)
4164  // below amended for version 0.6
4166  {
4167  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4168  }
4169  else if(Next.SigAspect == TTrackElement::TwoAspect)
4170  {
4171  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4172  }
4173  else if(Next.SigAspect == TTrackElement::GroundSignal)
4174  {
4175  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4176  }
4177  else // 4 aspect
4178  {
4179  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4180  }
4181  break;
4182  }
4183  }
4184  }
4185  else
4186  {
4187  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4188  }
4189  }
4190  }
4191  if(OldTransparentColour != clB5G5R5)
4192  {
4193  Utilities->clTransparent = OldTransparentColour; // restore
4196  }
4197  Utilities->CallLogPop(1533);
4198 }
4199 
4200 // ---------------------------------------------------------------------------
4201 
4202 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4203 {
4204  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4205  if(UserGraphicVector.empty())
4206  {
4207  Utilities->CallLogPop(2192);
4208  return;
4209  }
4210  else
4211  {
4212  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4213  {
4214  Bitmap->Canvas->CopyMode = cmSrcCopy;
4215  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4216  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4217  }
4218  }
4219  Utilities->CallLogPop(2193);
4220 }
4221 
4222 // ---------------------------------------------------------------------------
4223 
4224 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4225 /*
4226  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4227  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4228 */
4229 {
4230  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4231 // need to change graphics back to black on white if have a dark background
4232  TColor OldTransparentColour = Utilities->clTransparent;
4233 
4235  {
4236  Utilities->clTransparent = TColor(0xFFFFFF); // white
4239  }
4240  TTrackElement Next;
4241 
4242  Bitmap->Canvas->CopyMode = cmSrcCopy;
4244  Graphics::TBitmap *GraphicOutput;
4245 
4246  while(ReturnNextInactiveTrackElement(3, Next))
4247  {
4248  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4249  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4250  {
4251  if(Next.SpeedTag == 144) // level crossing
4252  {
4253  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4254  if(BaseElement == 1) // hor element
4255  {
4256  if(Next.Attribute == 1) // open to trains
4257  {
4258  GraphicOutput = RailGraphics->LCBothHor;
4259  }
4260  else // plot as closed to trains if in any other state
4261  {
4262  GraphicOutput = RailGraphics->LCBothVer;
4263  }
4264  }
4265  else // vert element
4266  {
4267  if(Next.Attribute == 1) // open to trains
4268  {
4269  GraphicOutput = RailGraphics->LCBothVer;
4270  }
4271  else // plot as closed to trains if in any other state
4272  {
4273  GraphicOutput = RailGraphics->LCBothHor;
4274  }
4275  }
4276  }
4277  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4278  }
4279  }
4280 
4281  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4282 
4283  NextTrackElementPtr = TrackVector.begin();
4284  while(ReturnNextTrackElement(3, Next))
4285  {
4286  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4287  {
4288  if(Next.TrackType == Points) // plot active fillet
4289  {
4290  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4291  if(Next.SpeedTag < 28)
4292  {
4293  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4295  }
4296  else if(Next.SpeedTag < 132)
4297  {
4298  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4300  }
4301  else
4302  {
4303  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4305  }
4306  if(Next.Failed) //added at v2.13.0
4307  {
4308  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4310  }
4311 
4312  }
4313  else if(Next.TrackType == GapJump) // plot as connected
4314  {
4315  if(Next.SpeedTag == 88)
4316  {
4317  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4318  }
4319  else if(Next.SpeedTag == 89)
4320  {
4321  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4322  }
4323  else if(Next.SpeedTag == 90)
4324  {
4325  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4326  }
4327  else if(Next.SpeedTag == 91)
4328  {
4329  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4330  }
4331  else if(Next.SpeedTag == 92)
4332  {
4333  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4334  }
4335  else if(Next.SpeedTag == 93)
4336  {
4337  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4338  }
4339  else if(Next.SpeedTag == 94)
4340  {
4341  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4342  }
4343  else if(Next.SpeedTag == 95)
4344  {
4345  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4346  }
4347  }
4348  else if(Next.TrackType == SignalPost) //plot in correct colour
4349  {
4350  for(int x = 0; x < 40; x++)
4351  {
4352  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4353  {
4354  //plot blank first, then plot platform if present - (always not striped for operating railway)
4355  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4356  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4357  int HOffset = 0;
4358  if(Next.SpeedTag > 73)
4359  {
4360  HOffset = 5;
4361  }
4362  else if(Next.SpeedTag == 71)
4363  {
4364  HOffset = 9;
4365  }
4366  int VOffset = 0;
4367  if(Next.SpeedTag == 69)
4368  {
4369  VOffset = 9;
4370  }
4371  else if(Next.SpeedTag == 72)
4372  {
4373  VOffset = 5;
4374  }
4375  else if(Next.SpeedTag == 74)
4376  {
4377  VOffset = 5;
4378  }
4379  Graphics::TBitmap *GraphicPtr;
4380  if(Next.SpeedTag > 71)
4381  {
4382  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4383  }
4384  else if(Next.SpeedTag < 70)
4385  {
4386  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4387  }
4388  else
4389  {
4390  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4391  }
4392  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4393  // plot special signal platform if present
4394  Graphics::TBitmap* SignalPlatformGraphic;
4395  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4396  {
4397  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4398  }
4399  if(!Next.Failed)
4400  {
4401  // now plot signal (double yellow overwrites most of signal platform if present)
4402  // below amended for version 0.6
4404  {
4405  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4406  }
4407  else if(Next.SigAspect == TTrackElement::TwoAspect)
4408  {
4409  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4410  }
4411  else if(Next.SigAspect == TTrackElement::GroundSignal)
4412  {
4413  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4414  }
4415  else // 4 aspect
4416  {
4417  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4418  }
4419  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4420  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4421  {
4422  if(Next.SpeedTag == 68)
4423  {
4424  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4425  }
4426  if(Next.SpeedTag == 69)
4427  {
4428  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4429  }
4430  if(Next.SpeedTag == 70)
4431  {
4432  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4433  }
4434  if(Next.SpeedTag == 71)
4435  {
4436  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4437  }
4438  if(Next.SpeedTag == 72)
4439  {
4440  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4441  }
4442  if(Next.SpeedTag == 73)
4443  {
4444  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4445  }
4446  if(Next.SpeedTag == 74)
4447  {
4448  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4449  }
4450  if(Next.SpeedTag == 75)
4451  {
4452  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4453  }
4454  }
4455  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4456  {
4457  for(int x = 0; x < 40; x++)
4458  {
4459  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4460  {
4461  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4462  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4463  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4464  // plot special signal platform if present
4465  Graphics::TBitmap* SignalPlatformGraphic;
4466  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4467  {
4468  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4469  }
4470  // now plot signal
4471  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4472  break;
4473  }
4474  }
4475  }
4476  break;
4477  }
4478  else //added at v2.13.0
4479  {
4481  {
4482  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4483  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4484  }
4485  else
4486  {
4487  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4488  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4489  }
4490  break;
4491  }
4492  }
4493  }
4494  }
4495  else
4496  {
4497  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4498  if(Next.Failed) //added at v2.13.0
4499  {
4500  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4502  }
4503  }
4504  }
4505  }
4506  if(OldTransparentColour != clB5G5R5)
4507  {
4508  Utilities->clTransparent = OldTransparentColour; // restore
4511  }
4512  Utilities->CallLogPop(1701);
4513 }
4514 
4515 // ---------------------------------------------------------------------------
4516 
4517 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4518 {
4519  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4520  for(unsigned int x = 0; x < TrackVector.size(); x++)
4521  {
4522  if(TrackElementAt(1093, x).TrackType == GapJump)
4523  {
4524  if(TrackElementAt(1094, x).Conn[0] > -1)
4525  {
4526  continue; // to next 'x' value as this element has already been set
4527  }
4528  // here if identify a GapJump element not yet set
4529  GapPos = x;
4530  GapHLoc = TrackElementAt(1095, x).HLoc;
4531  GapVLoc = TrackElementAt(1096, x).VLoc;
4532  // highlight it
4534  Utilities->CallLogPop(469);
4535  return(true);
4536  }
4537  }
4538  Utilities->CallLogPop(470);
4539  return(false);
4540 }
4541 
4542 // ---------------------------------------------------------------------------
4543 
4544 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4545 {
4546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4547  AnsiString(VLoc));
4548  int Position;
4549  TTrackElement TrackElement;
4550 
4551  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4552  {
4553  Utilities->CallLogPop(471);
4554  return(false); // not found
4555  }
4556  if(TrackElement.TrackType != GapJump)
4557  {
4558  Utilities->CallLogPop(472);
4559  return(false); // found something but not a gap
4560  }
4561  if(Position == GapPos)
4562  {
4563  Utilities->CallLogPop(473);
4564  return(false); // selected original gap
4565  }
4566  if(TrackElementAt(1097, Position).Conn[0] != -1)
4567  {
4568  Utilities->CallLogPop(474);
4569  return(false); // already selected
4570  }
4571  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4572  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4573  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4574  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4575 // now highlight the selected location
4576  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4577  Utilities->CallLogPop(475);
4578  return(true);
4579 }
4580 
4581 // ---------------------------------------------------------------------------
4582 
4583 bool TTrack::GapsUnset(int Caller)
4584 // returns true if there are gaps and any are unset
4585 {
4586  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4587  if(TrackVector.size() == 0)
4588  {
4589  Utilities->CallLogPop(476);
4590  return(false);
4591  }
4592  for(unsigned int x = 0; x < TrackVector.size(); x++)
4593  {
4594  if(TrackElementAt(1102, x).TrackType == GapJump)
4595  {
4596  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4597  {
4598  Utilities->CallLogPop(477);
4599  return(true);
4600  }
4601  else // set, but may not have matching element, or that element may not be set
4602  {
4603  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4604  // check that the element pointed to by the gap link is a GapJump
4605  {
4606  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4607  Utilities->CallLogPop(1137);
4608  return(false);
4609  }
4610 // here if gap connection is itself a GapJump
4611  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4612  // check that the element pointed to by the gap link is a GapJump & that its gap link
4613  // points back to 'x'
4614  {
4615  Utilities->CallLogPop(478);
4616  return(true);
4617  }
4618 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4619  }
4620  } // if(TrackElementAt(, x).TrackType == GapJump)
4621 
4622  } // for x...
4623  Utilities->CallLogPop(479);
4624  return(false);
4625 }
4626 
4627 // ---------------------------------------------------------------------------
4628 
4629 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4630 {
4631  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4632  for(unsigned int x = 0; x < TrackVector.size(); x++)
4633  {
4634  if(TrackElementAt(1110, x).TrackType == GapJump)
4635  {
4636  Utilities->CallLogPop(1105);
4637  return(false);
4638  }
4639  }
4640  Utilities->CallLogPop(1106);
4641  return(true);
4642 }
4643 
4644 // ---------------------------------------------------------------------------
4645 
4646 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4647 {
4648  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4649  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4650  {
4651  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4652  {
4653  Utilities->CallLogPop(1107);
4654  return(false);
4655  }
4656  }
4657  for(unsigned int x = 0; x < TrackVector.size(); x++)
4658  {
4659  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4660  {
4661  Utilities->CallLogPop(1108);
4662  return(false);
4663  }
4664  }
4665  Utilities->CallLogPop(1109);
4666  return(true);
4667 }
4668 
4669 // ---------------------------------------------------------------------------
4670 
4672 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4673 // returns false otherwise or if there are no NamedLocationElements
4674 {
4675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4676  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4677  {
4678  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4679  {
4680  if(InactiveTrackElementAt(139, x).LocationName == "")
4681  {
4682  Utilities->CallLogPop(1110);
4683  return(true);
4684  }
4685  }
4686  }
4687  for(unsigned int x = 0; x < TrackVector.size(); x++)
4688  {
4689  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4690  {
4691  if(TrackElementAt(1113, x).LocationName == "")
4692  {
4693  Utilities->CallLogPop(1111);
4694  return(true);
4695  }
4696  }
4697  }
4698  Utilities->CallLogPop(1112);
4699  return(false);
4700 }
4701 
4702 // ---------------------------------------------------------------------------
4703 
4704 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4705 {
4706  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4707  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4708  Utilities->CallLogPop(480);
4709 }
4710 
4711 // ---------------------------------------------------------------------------
4712 
4714 {
4715  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4716  if(TrackVector.size() == 0)
4717  {
4718  Utilities->CallLogPop(481);
4719  return;
4720  }
4721  for(unsigned int x = 0; x < TrackVector.size(); x++)
4722  {
4723  if(TrackElementAt(1114, x).TrackType == GapJump)
4724  {
4725  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4726  {
4727  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4728  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4729  {
4730  TrackElementAt(1118, x).Conn[0] = -1;
4731  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4732  continue; // to next 'x'
4733  }
4734 // here if gap connection is itself a GapJump
4735  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4736  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4737  // if not clear Conns & CLks
4738  {
4739  TrackElementAt(1121, x).Conn[0] = -1;
4740  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4741  continue; // to next 'x'
4742  }
4743 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4744 // hence no more action needed on these Conns & CLks
4745  }
4746  } // else //gap jump
4747 
4748  } // for x...
4749 // throw Exception("Test Exception");//test
4750  Utilities->CallLogPop(482);
4751 }
4752 
4753 // ---------------------------------------------------------------------------
4754 
4755 void TTrack::ResetSignals(int Caller)
4756 {
4757  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4758  for(unsigned int x = 0; x < TrackVector.size(); x++)
4759  {
4760  if(TrackElementAt(1123, x).TrackType == SignalPost)
4761  {
4762  TrackElementAt(1124, x).Attribute = 0;
4763  TrackElementAt(1514, x).Failed = false;
4764  }
4765  }
4766  FailedSignalsVector.clear();
4767  Utilities->CallLogPop(483);
4768 }
4769 
4770 // ---------------------------------------------------------------------------
4771 
4772 void TTrack::ResetPoints(int Caller)
4773 {
4774  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4775  for(unsigned int x = 0; x < TrackVector.size(); x++)
4776  {
4777  if((TrackElementAt(1125, x).TrackType == Points) && (TrackElementAt(1571, x).Failed))
4778  {
4779  TrackElementAt(1126, x).Attribute = 0;
4780  TrackElementAt(1515, x).Failed = false;
4783  TrackElementAt(1569, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4784  TrackElementAt(1570, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 = -1; //added at v2.15.0
4785  }
4786  }
4787  FailedPointsVector.clear();
4788  Utilities->CallLogPop(484);
4789 }
4790 
4791 // ---------------------------------------------------------------------------
4792 
4793 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4794 {
4795  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4796  for(unsigned int x = 0; x < TrackVector.size(); x++)
4797  {
4798  if((TrackElementAt(1554, x).TrackType == Simple) && (TrackElementAt(1555, x).Failed))
4799  {
4800  TrackElementAt(1556, x).Failed = false;
4802  TrackElementAt(1573, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4803  }
4804  }
4805  TSRVector.clear();
4806  Utilities->CallLogPop(2550);
4807 }
4808 
4809 // ---------------------------------------------------------------------------
4810 
4811 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4812 {
4813  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4814  if(TrackVector.empty())
4815  {
4816  TrackMap.clear();
4817  Utilities->CallLogPop(485);
4818  return(true);
4819  }
4820 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4821  THVPair TrackMapKeyPair;
4822 
4823  NewVector.clear();
4824  TTrackMapIterator TrackMapPtr;
4825 
4826  if(!TrackMap.empty())
4827  {
4828  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4829  {
4830  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4831  }
4832  }
4833  if(NewVector.size() != TrackMap.size())
4834  {
4835  throw Exception("Error - Map & Vector different sizes");
4836  }
4837  unsigned int NonZeroCount = 0;
4838 
4839  for(unsigned int x = 0; x < TrackVector.size(); x++)
4840  {
4841  if(TrackElementAt(1127, x).TrackType != Erase)
4842  {
4843  NonZeroCount++;
4844  }
4845  }
4846  if(NewVector.size() != NonZeroCount)
4847  {
4848  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4849  }
4851  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4852  TTrackMapEntry TrackMapEntry;
4853 
4854  for(unsigned int x = 0; x < TrackVector.size(); x++)
4855  {
4856  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4857  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4858  TrackMapEntry.first = TrackMapKeyPair;
4859  TrackMapEntry.second = x;
4860  if(!(TrackMap.insert(TrackMapEntry).second))
4861  {
4862  throw Exception("Error - map insertion failure, TrackVector in error");
4863  }
4864  }
4865 // All track now relocated in TrackVector, reset all Conns & CLks
4866  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4867  {
4868  for(unsigned int y = 0; y < 4; y++)
4869  {
4870  TrackElementAt(1130, x).Conn[y] = -1;
4871  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4872  }
4873  }
4874  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4875  CheckMapAndTrack(4); // test
4876  CheckMapAndInactiveTrack(4); // test
4877  CheckLocationNameMultiMap(8); // test
4878  if(!ResetGapsFromGapMap(1))
4879  {
4880  Utilities->CallLogPop(489);
4881  return(false);
4882  }
4883  Utilities->CallLogPop(490);
4884  return(true);
4885 }
4886 
4887 // ---------------------------------------------------------------------------
4888 
4889 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4890 {
4891  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4892  GapMap.clear();
4893  THVPair GapMapKeyPair, GapMapValuePair;
4894  TGapMapEntry GapMapEntry;
4895 
4896  for(unsigned int x = 0; x < TrackVector.size(); x++)
4897  {
4898  if(TrackElementAt(1132, x).TrackType == GapJump)
4899  {
4900  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4901  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4902  GapMapEntry.first = GapMapKeyPair;
4903  if(TrackElementAt(1135, x).Conn[0] == -1)
4904  {
4905  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4906  }
4907  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4908  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4909  GapMapEntry.second = GapMapValuePair;
4910  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4911  {
4912  GapMap.insert(GapMapEntry);
4913  }
4914  }
4915  }
4916  Utilities->CallLogPop(492);
4917 }
4918 
4919 // ---------------------------------------------------------------------------
4920 
4921 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4922 {
4923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4924 
4925 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
4926  LocError = false;
4927  bool TrackElementPositionsOK = true;
4928 
4929  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4930  {
4931  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4932  {
4933  continue; // skip blank elements
4934  }
4935 // check footcrossing linkages
4936  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4937  {
4938  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4939  {
4940  ShowMessage(
4941  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4942  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4943  "can't connect to an underpass or vice versa)");
4944  HLoc = TrackElementAt(1141, x).HLoc;
4945  VLoc = TrackElementAt(1142, x).VLoc;
4946  LocError = true;
4947  Utilities->CallLogPop(493);
4948  return(false);
4949  }
4950  }
4951  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4952  {
4953  if(TrackElementAt(1143, x).Link[y] <= 0)
4954  {
4955  continue; // no link
4956  }
4957  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4958  {
4959  continue; // buffer
4960  }
4961  if(TrackElementAt(1146, x).Config[y] == Gap)
4962  {
4963  continue; // gaps set later from GapMap
4964  }
4965  // get required H & V for track element joining link 'y'
4966  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4967  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4968  // find track element if present
4969  bool ConnectionFoundFlag;
4970  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4971  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4972  {
4973  ShowMessage("Can't have a track element adjacent to a continuation exit");
4974  HLoc = TrackElementAt(1152, x).HLoc;
4975  VLoc = TrackElementAt(1153, x).VLoc;
4976  LocError = true;
4977  if(FinalCall)
4978  {
4979  throw Exception("Error in final track linkage - continuation adjacent to another element");
4980  }
4981  Utilities->CallLogPop(1539);
4982  return(false);
4983  }
4984  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4985  {
4986  continue;
4987  }
4988  if(ConnectionFoundFlag)
4989  {
4990  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
4991  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4992 
4993  bool ExitSignal = false;
4994  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
4995  {
4996  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
4997  {
4998  ExitSignal = true;
4999  }
5000  }
5001  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
5002  {
5003  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
5004  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
5005  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
5006  TrackElementPositionsOK = false;
5007  }
5008  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
5009  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
5010  {
5011  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
5012  // need room for a train (2 elements) without fouling points or signals
5013  TrackElementPositionsOK = false;
5014  }
5015  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
5016  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
5017  {
5018  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
5019  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5020  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5021  // be named but needs the adjacent element named too
5022  TrackElementPositionsOK = false;
5023  }
5024  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5025  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5026  {
5027  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5028  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5029  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5030  TrackElementPositionsOK = false;
5031  }
5032 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5033 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
5034  {
5035  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5036  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5037  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5038  TrackElementPositionsOK = false;
5039  }*/
5040  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5041  {
5042  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5043  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5044  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5045  TrackElementPositionsOK = false;
5046  }
5047  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5048  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5049  {
5050  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5051  TrackElementPositionsOK = false;
5052  }
5053  // if failed then set the invert values for the offending element
5054  if(!TrackElementPositionsOK)
5055  {
5056  HLoc = TrackElementAt(1183, x).HLoc;
5057  VLoc = TrackElementAt(1184, x).VLoc;
5058  LocError = true;
5059  if(FinalCall)
5060  {
5061  throw Exception("Error in track element positions in FinalCall");
5062  }
5063  Utilities->CallLogPop(494);
5064  return(false);
5065  }
5066  }
5067  // no 'else' here, if there's no link then will be picked up in 2nd pass
5068  }
5069  } // for(unsigned int x=0;x<TrackVector.size();x++)
5070 
5071 
5072 //2nd pass - looking for missing connections
5073  LocError = false;
5074  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5075  {
5076  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5077  {
5078  continue; // skip blank elements
5079  }
5080  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5081  {
5082  if(TrackElementAt(1440, x).Link[y] <= 0)
5083  {
5084  continue; // no link
5085  }
5086  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5087  {
5088  continue; // buffer
5089  }
5090  if(TrackElementAt(1443, x).Config[y] == Gap)
5091  {
5092  continue; // gaps set later from GapMap
5093  }
5094  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5095  {
5096  continue; //continuation
5097  }
5098  // get required H & V for track element joining link 'y'
5099  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5100  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5101  // find track element if present
5102  bool ConnectionFoundFlag;
5103  bool LinkMatchFound = false;
5104  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag); //this is the joining element at link 'y'
5105  // if there isn't a connection set the invert values for the offending element
5106  if(ConnectionFoundFlag) //set the ConnLinkPos values
5107  {
5108  for(unsigned int a = 0; a < 4; a++) //links for the joining element at this element's link 'y'
5109  {
5110  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5111  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5112  {
5113  TrackElementAt(1182, x).ConnLinkPos[y] = a; //for points, 'y == 0' and 'y == 2' will be allocated same value for 'a'
5114  LinkMatchFound = true;
5115  break; //can only match 1 so can break
5116  }
5117  }
5118  if(!LinkMatchFound)
5119  {
5120  HLoc = TrackElementAt(1446, x).HLoc;
5121  VLoc = TrackElementAt(1447, x).VLoc;
5122  LocError = true;
5123  if(FinalCall)
5124  {
5125  throw Exception("Error in final track linkage - - no matching link found");
5126  }
5127  Utilities->CallLogPop(495);
5128  return(false);
5129  }
5130  }
5131  else //error
5132  {
5133  HLoc = TrackElementAt(1185, x).HLoc;
5134  VLoc = TrackElementAt(1186, x).VLoc;
5135  LocError = true;
5136  if(FinalCall)
5137  {
5138  throw Exception("Error in final track linkage - connection not found");
5139  }
5140  Utilities->CallLogPop(2443);
5141  return(false);
5142  }
5143  }
5144  }
5145 //end of 2nd pass
5146 
5147  if(FinalCall)
5148  {
5151  }
5152 
5153 // confirmatiory checks that all ok - or throw error
5154  bool ConnErrorFlag = false;
5155 
5156  for(unsigned int x = 0; x < TrackVector.size(); x++)
5157  {
5158  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5159  {
5160  ConnErrorFlag = true;
5161  }
5162  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5163  {
5164  ConnErrorFlag = true;
5165  }
5166  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5167  {
5168  ConnErrorFlag = true;
5169  }
5170  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5171  {
5172  ConnErrorFlag = true;
5173  }
5174  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5175  {
5176  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5177  {
5178  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1) ||
5179  (TrackElementAt(1637, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1638, x).StationEntryStopLinkPos4 != -1))
5180  {
5181  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5182  }
5183  }
5184  }
5185  }
5186  if(ConnErrorFlag)
5187  {
5188  if(FinalCall)
5189  {
5190  throw Exception("ConnError in LinkTrack - Final");
5191  }
5192  else
5193  {
5194  throw Exception("ConnError in LinkTrack - Precheck");
5195  }
5196  }
5197  bool CLkErrorFlag = false;
5198 
5199  for(unsigned int x = 0; x < TrackVector.size(); x++)
5200  {
5201  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5202  {
5203  CLkErrorFlag = true;
5204  }
5205  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5206  {
5207  CLkErrorFlag = true;
5208  }
5209  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5210  {
5211  CLkErrorFlag = true;
5212  }
5213  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5214  {
5215  CLkErrorFlag = true;
5216  }
5217  }
5218 
5219  if(CLkErrorFlag)
5220  {
5221  if(FinalCall)
5222  {
5223  throw Exception("CLkError in LinkTrack - Final");
5224  }
5225  else
5226  {
5227  throw Exception("CLkError in LinkTrack - Precheck");
5228  }
5229  }
5230 
5231 // set element lengths to min of 10m
5232  for(unsigned int x = 0; x < TrackVector.size(); x++)
5233  {
5234  if(TrackElementAt(1214, x).TrackType == Erase)
5235  {
5236  continue; // skip blank elements
5237  }
5238  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5239  {
5240  TrackElementAt(1216, x).Length01 = 10;
5241  }
5242  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5243  {
5244  TrackElementAt(1219, x).Length23 = 10;
5245  }
5246  }
5247 
5248  if(FinalCall) // ONLY at FinalCall, no point calling twice
5249  {
5250  CalcHLocMinEtc(3);
5251  }
5252 
5253  Utilities->CallLogPop(497);
5254  return(true);
5255 }
5256 
5257 // ---------------------------------------------------------------------------
5258 
5259 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5260 {
5261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5262  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5263  {
5264  if(TrackElementAt(1220, x).TrackType == Erase)
5265  {
5266  continue; // skip blank elements
5267 
5268  }
5269 // check footcrossing linkages
5270  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5271  {
5272  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5273  {
5274  Utilities->CallLogPop(1127);
5275  return(false);
5276  }
5277  }
5278  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5279  {
5280  if(TrackElementAt(1223, x).Link[y] <= 0)
5281  {
5282  continue; // no link
5283  }
5284  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5285  {
5286  continue; // buffer
5287  }
5288  if(TrackElementAt(1226, x).Config[y] == Gap)
5289  {
5290  continue; // gaps set later from GapMap
5291 
5292  }
5293  // get required H & V for track element joining link 'y'
5294  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5295  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5296  // find track element if present
5297  bool ConnectionFoundFlag;
5298  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5299  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5300  {
5301  if(FinalCall)
5302  {
5303  throw Exception("Error in final track linkage - continuation adjacent to another element");
5304  }
5305  Utilities->CallLogPop(1540);
5306  return(false);
5307  }
5308  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5309  {
5310  continue;
5311  }
5312  if(ConnectionFoundFlag)
5313  {
5314  TrackElementAt(1234, x).Conn[y] = VecPos;
5315  bool LinkFoundFlag = false;
5316  // find connecting link in the newly found track element if there is one & make checks
5317  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5318  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5319  {
5320  Utilities->CallLogPop(1541);
5321  return(false);
5322  }
5323  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5324  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5325  {
5326  Utilities->CallLogPop(1542);
5327  return(false);
5328  }
5329  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5330  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5331  {
5332  Utilities->CallLogPop(1543);
5333  return(false);
5334  }
5335  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5336  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5337  {
5338  Utilities->CallLogPop(1981);
5339  return(false);
5340  }
5341 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5342  else if(TrackElementAt(, x).TrackType == Continuation)
5343  {
5344  int H = TrackElementAt(, x).HLoc;
5345  int V = TrackElementAt(, x).VLoc;
5346  bool FoundFlag = false;
5347  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5348  if(FoundFlag)
5349  {
5350  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5351  {
5352  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5353  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5354  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5355  if(FoundFlag)
5356  {
5357  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5358  {
5359  Utilities->CallLogPop();
5360  return false;
5361  }
5362  }
5363  else
5364  {
5365  Utilities->CallLogPop();
5366  return false;
5367  }
5368  }
5369  }
5370  }
5371 */
5372  for(unsigned int a = 0; a < 4; a++)
5373  {
5374  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5375  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5376  {
5377  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5378  // note - this ensures that if the connecting element is a leading point
5379  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5380  // (Points have the same link value for both [0] and [2])
5381  LinkFoundFlag = true;
5382  break; // stop after first find or will find later link for leading point
5383  }
5384  }
5385  if(!LinkFoundFlag)
5386  {
5387  if(FinalCall)
5388  {
5389  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5390  }
5391  Utilities->CallLogPop(1128);
5392  return(false);
5393  }
5394  }
5395  else // if(ConnectionFoundFlag)
5396  {
5397  if(FinalCall)
5398  {
5399  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5400  }
5401  Utilities->CallLogPop(1129);
5402  return(false);
5403  }
5404  }
5405  } // for(unsigned int x=0;x<TrackVector.size();x++)
5406 
5407  if(FinalCall)
5408  {
5411  }
5412 // final check
5413  bool ConnErrorFlag = false;
5414 
5415  for(unsigned int x = 0; x < TrackVector.size(); x++)
5416  {
5417  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5418  {
5419  ConnErrorFlag = true;
5420  }
5421  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5422  {
5423  ConnErrorFlag = true;
5424  }
5425  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5426  {
5427  ConnErrorFlag = true;
5428  }
5429  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5430  {
5431  ConnErrorFlag = true;
5432  }
5433  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5434  {
5435  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5436  {
5437  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1) ||
5438  (TrackElementAt(1639, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1640, x).StationEntryStopLinkPos4 != -1))
5439  {
5440  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5441  }
5442  }
5443  }
5444  }
5445  if(ConnErrorFlag)
5446  {
5447  if(FinalCall)
5448  {
5449  throw Exception("ConnError in LinkTrack - Final");
5450  }
5451  else
5452  {
5453  throw Exception("ConnError in LinkTrack - Precheck");
5454  }
5455  }
5456  bool CLkErrorFlag = false;
5457 
5458  for(unsigned int x = 0; x < TrackVector.size(); x++)
5459  {
5460  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5461  {
5462  CLkErrorFlag = true;
5463  }
5464  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5465  {
5466  CLkErrorFlag = true;
5467  }
5468  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5469  {
5470  CLkErrorFlag = true;
5471  }
5472  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5473  {
5474  CLkErrorFlag = true;
5475  }
5476  }
5477 
5478  if(CLkErrorFlag)
5479  {
5480  if(FinalCall)
5481  {
5482  throw Exception("CLkError in LinkTrack - Final");
5483  }
5484  else
5485  {
5486  throw Exception("CLkError in LinkTrack - Precheck");
5487  }
5488  }
5489 // set element lengths to min of 10m
5490  for(unsigned int x = 0; x < TrackVector.size(); x++)
5491  {
5492  if(TrackElementAt(1284, x).TrackType == Erase)
5493  {
5494  continue; // skip blank elements
5495  }
5496  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5497  {
5498  TrackElementAt(1286, x).Length01 = 10;
5499  }
5500  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5501  {
5502  TrackElementAt(1289, x).Length23 = 10;
5503  }
5504  }
5505 
5506  if(FinalCall) // ONLY at FinalCall, no point calling twice
5507  {
5508  CalcHLocMinEtc(7);
5509  }
5510  Utilities->CallLogPop(1130);
5511  return(true);
5512 }
5513 
5514 // ---------------------------------------------------------------------------
5515 
5516 bool TTrack::IsTrackLinked(int Caller) // not used any more
5517 {
5518  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5519  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5520  {
5521  if(TrackElementAt(1290, x).TrackType == Erase)
5522  {
5523  Utilities->CallLogPop(498);
5524  return(false);
5525  }
5526 // check foot linkages
5527  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5528  {
5529  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5530  {
5531  Utilities->CallLogPop(499);
5532  return(false);
5533  }
5534  }
5535  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5536  {
5537  if(TrackElementAt(1293, x).Link[y] <= 0)
5538  {
5539  continue; // no link
5540  }
5541  if(TrackElementAt(1294, x).Config[y] == End)
5542  {
5543  continue; // buffer or continuation
5544  }
5545  if(TrackElementAt(1295, x).Config[y] == Gap)
5546  {
5547  continue; // gaps set later from GapMap
5548 
5549  }
5550  // get required H & V for track element joining link 'y'
5551  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5552  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5553  // find track element if present
5554  bool ConnectionFoundFlag = false;
5555  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5556  if(ConnectionFoundFlag)
5557  {
5558  TrackElementAt(1300, x).Conn[y] = VecPos;
5559  // find connecting link in the newly found track element if there is one & make buffer check
5560  bool LinkFoundFlag = false;
5561  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5562  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5563  {
5564  Utilities->CallLogPop(500);
5565  return(false);
5566  }
5567  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5568  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5569  {
5570  Utilities->CallLogPop(501);
5571  return(false);
5572  }
5573  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5574  {
5575  Utilities->CallLogPop(502);
5576  return(false);
5577  }
5578  else
5579  {
5580  for(unsigned int a = 0; a < 4; a++)
5581  {
5582  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5583  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5584  {
5585  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5586  // note - this ensures that if the connecting element is a leading point
5587  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5588  // (Points have the same link value for both [0] and [2])
5589  LinkFoundFlag = true;
5590  break; // stop after first find or will find later link for leading point
5591  }
5592  }
5593  }
5594  if(!LinkFoundFlag)
5595  {
5596  Utilities->CallLogPop(503);
5597  return(false);
5598  }
5599  }
5600  else // if(ConnectionFoundFlag)
5601  {
5602  Utilities->CallLogPop(504);
5603  return(false);
5604  }
5605  }
5606  } // for(unsigned int x=0;x<TrackVector.size();x++)
5607 
5608 // final check
5609  bool ConnErrorFlag = false;
5610 
5611  for(unsigned int x = 0; x < TrackVector.size(); x++)
5612  {
5613  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5614  {
5615  ConnErrorFlag = true;
5616  }
5617  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5618  {
5619  ConnErrorFlag = true;
5620  }
5621  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5622  {
5623  ConnErrorFlag = true;
5624  }
5625  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5626  {
5627  ConnErrorFlag = true;
5628  }
5629  }
5630  if(ConnErrorFlag)
5631  {
5632  Utilities->CallLogPop(505);
5633  return(false);
5634  }
5635  bool CLkErrorFlag = false;
5636 
5637  for(unsigned int x = 0; x < TrackVector.size(); x++)
5638  {
5639  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5640  {
5641  CLkErrorFlag = true;
5642  }
5643  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5644  {
5645  CLkErrorFlag = true;
5646  }
5647  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5648  {
5649  CLkErrorFlag = true;
5650  }
5651  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5652  {
5653  CLkErrorFlag = true;
5654  }
5655  }
5656 
5657  if(CLkErrorFlag)
5658  {
5659  Utilities->CallLogPop(506);
5660  return(false);
5661  }
5662  Utilities->CallLogPop(507);
5663  return(true);
5664 }
5665 
5666 // ---------------------------------------------------------------------------
5667 
5669 {
5670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5671  int Position1, Position2;
5672  TTrackElement TrackElement1, TrackElement2;
5673  TGapMapIterator GapMapPtr;
5674 
5675  if(!GapMap.empty())
5676  {
5677  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5678  {
5679  int HLoc1 = GapMapPtr->first.first;
5680  int VLoc1 = GapMapPtr->first.second;
5681  int HLoc2 = GapMapPtr->second.first;
5682  int VLoc2 = GapMapPtr->second.second;
5683  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5684  {
5685  throw Exception("Failed to find H & V for gap1, GapMap in error");
5686  }
5687  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5688  {
5689  throw Exception("Failed to find H & V for gap2, GapMap in error");
5690  }
5691  if(TrackElementAt(9, Position1).TrackType != GapJump)
5692  {
5693  throw Exception("Element at Pos1 not a gap, GapMap in error");
5694  }
5695  if(TrackElementAt(10, Position2).TrackType != GapJump)
5696  {
5697  throw Exception("Element at Pos2 not a gap, GapMap in error");
5698  }
5699  TrackElementAt(11, Position1).Conn[0] = Position2;
5700  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5701  TrackElementAt(13, Position2).Conn[0] = Position1;
5702  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5703  }
5704  }
5705  Utilities->CallLogPop(510);
5706  return(true);
5707 }
5708 
5709 // ---------------------------------------------------------------------------
5710 
5711 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5712 {
5713 // TIMPair MapEntry;
5714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5715  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5716  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5717  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5718  TLocationNameMultiMapEntry LocationNameEntry;
5719 
5720  LocationNameEntry.first = TrackElement.LocationName;
5721  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5722  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5723  {
5724 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5725 // could arise when loading old railways with multiple NonStationNamedLocs
5726  bool FoundFlag = false;
5727  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5728  if(FoundFlag)
5729  {
5730  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5731  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5732  {
5733  Utilities->CallLogPop(1813);
5734  return;
5735  }
5736  }
5737  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5738  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5739  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5740  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5741  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5742  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5743  if(TrackElement.FixedNamedLocationElement)
5744  {
5745  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5746  LocationNameMultiMap.insert(LocationNameEntry);
5747  }
5748  if(TrackElement.HLoc < HLocMin)
5749  {
5750  HLocMin = TrackElement.HLoc;
5751  }
5752  if(TrackElement.HLoc > HLocMax)
5753  {
5754  HLocMax = TrackElement.HLoc;
5755  }
5756  if(TrackElement.VLoc < VLocMin)
5757  {
5758  VLocMin = TrackElement.VLoc;
5759  }
5760  if(TrackElement.VLoc > VLocMax)
5761  {
5762  VLocMax = TrackElement.VLoc;
5763  }
5764  }
5765  else
5766  {
5767 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5768 // shouldn't arise but leave in as a safeguard
5769  bool FoundFlag = false;
5770  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5771  if(FoundFlag)
5772  {
5773  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5774  {
5775  Utilities->CallLogPop(1814);
5776  return;
5777  }
5778  }
5779  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5780  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5781  {
5782  TrackMapKeyPair.first = TrackElement.HLoc;
5783  TrackMapKeyPair.second = TrackElement.VLoc;
5784  TrackMapEntry.first = TrackMapKeyPair;
5785  TrackMapEntry.second = TrackVector.size() - 1;
5786  TrackMap.insert(TrackMapEntry);
5787  if(TrackElement.FixedNamedLocationElement)
5788  {
5789  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5790  LocationNameMultiMap.insert(LocationNameEntry);
5791  }
5792  if(TrackElement.HLoc < HLocMin)
5793  {
5794  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5795  }
5796  if(TrackElement.HLoc > HLocMax)
5797  {
5798  HLocMax = TrackElement.HLoc;
5799  }
5800  if(TrackElement.VLoc < VLocMin)
5801  {
5802  VLocMin = TrackElement.VLoc;
5803  }
5804  if(TrackElement.VLoc > VLocMax)
5805  {
5806  VLocMax = TrackElement.VLoc;
5807  }
5808  }
5809  }
5810 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5811 // CheckMapAndInactiveTrack(6);//test
5812 
5813 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5814 // with the Platforms until layout fully loaded
5815  Utilities->CallLogPop(511);
5816 }
5817 
5818 // ---------------------------------------------------------------------------
5819 
5820 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5821 {
5822  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5823  AnsiString(VLoc));
5824  THVPair TrackMapKeyPair;
5825 
5826  FoundFlag = false;
5827  TTrackMapIterator TrackMapPtr;
5828 
5829  TrackMapKeyPair.first = HLoc;
5830  TrackMapKeyPair.second = VLoc;
5831  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5832  if(TrackMapPtr == TrackMap.end())
5833  {
5834  Utilities->CallLogPop(512);
5835  return(-1); // nothing found
5836  }
5837  else
5838  {
5839  FoundFlag = true;
5840  Utilities->CallLogPop(513);
5841  return(TrackMapPtr->second);
5842  }
5843 }
5844 
5845 // ---------------------------------------------------------------------------
5846 
5847 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5848 {
5849  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5850  AnsiString(VLoc));
5851  THVPair TrackMapKeyPair;
5852  TTrackMapIterator TrackMapPtr;
5853 
5854  TrackMapKeyPair.first = HLoc;
5855  TrackMapKeyPair.second = VLoc;
5856  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5857  if(TrackMapPtr == TrackMap.end())
5858  {
5859  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5860  throw Exception(Message);
5861  }
5862  else
5863  {
5864  Utilities->CallLogPop(1943);
5865  return(TrackElementAt(871, TrackMapPtr->second));
5866  }
5867 }
5868 
5869 // ---------------------------------------------------------------------------
5870 
5871 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5872 { //modded at v2.9.2 to make Map & Vector references
5873  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5874  AnsiString(VLoc));
5875  THVPair MapKeyPair;
5876  TTrackMapIterator MapPtr;
5877 
5878  MapKeyPair.first = HLoc;
5879  MapKeyPair.second = VLoc;
5880  MapPtr = Map.find(MapKeyPair);
5881  if(MapPtr == Map.end())
5882  {
5883  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5884  throw Exception(Message);
5885  }
5886  else
5887  {
5888  Utilities->CallLogPop(2280);
5889  return(Vector.at(MapPtr->second));
5890  }
5891 }
5892 
5893 // ---------------------------------------------------------------------------
5894 
5896 {
5897  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5898  AnsiString(VLoc));
5899  THVPair InactiveTrackMapKeyPair;
5900  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5901 
5902  InactiveTrackMapKeyPair.first = HLoc;
5903  InactiveTrackMapKeyPair.second = VLoc;
5904  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5905  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5906  {
5907  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5908  throw Exception(Message);
5909  }
5910  else
5911  {
5912  Utilities->CallLogPop(1949);
5913  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5914  }
5915 }
5916 
5917 // ---------------------------------------------------------------------------
5918 
5919 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5920 {
5921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5922  bool Present = true;
5923  THVPair TrackMapKeyPair;
5924  TTrackMapIterator TrackMapPtr;
5925 
5926  TrackMapKeyPair.first = HLoc;
5927  TrackMapKeyPair.second = VLoc;
5928  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5929  if(TrackMapPtr == TrackMap.end())
5930  {
5931  Present = false;
5932  }
5933  Utilities->CallLogPop(2057);
5934  return(Present);
5935 }
5936 
5937 // ---------------------------------------------------------------------------
5938 
5939 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5940 {
5941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5942  AnsiString(VLoc));
5943  bool Present = true;
5944  THVPair InactiveTrackMapKeyPair;
5945  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5946 
5947  InactiveTrackMapKeyPair.first = HLoc;
5948  InactiveTrackMapKeyPair.second = VLoc;
5949  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5950  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5951  {
5952  Present = false;
5953  }
5954  Utilities->CallLogPop(2058);
5955  return(Present);
5956 }
5957 
5958 // ---------------------------------------------------------------------------
5959 
5960 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5961 // max number of elements is 2, for platforms
5962 // note that both elements of RetPair may be the same, if only one present in map
5963 {
5964  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5965  AnsiString(VLoc));
5966  THVPair InactiveTrackMapKeyPair;
5967  TIMPair RetPair;
5968  TInactiveTrackRange InactiveTrackRange;
5969 
5970  FoundFlag = false;
5971  InactiveTrackMapKeyPair.first = HLoc;
5972  InactiveTrackMapKeyPair.second = VLoc;
5973  if(InactiveTrack2MultiMap.empty())
5974  {
5975  RetPair.first = 0;
5976  RetPair.second = 0;
5977  Utilities->CallLogPop(1815);
5978  return(RetPair); // map empty
5979  }
5980  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5981  if(InactiveTrackRange.first == InactiveTrackRange.second)
5982  {
5983  RetPair.first = 0;
5984  RetPair.second = 0;
5985  Utilities->CallLogPop(514);
5986  return(RetPair); // nothing found
5987  }
5988  else
5989  {
5990  RetPair.first = InactiveTrackRange.first->second;
5991  RetPair.second = (--InactiveTrackRange.second)->second;
5992  FoundFlag = true;
5993  Utilities->CallLogPop(515);
5994  return(RetPair);
5995  }
5996 }
5997 
5998 // ---------------------------------------------------------------------------
5999 
6000 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
6001 {
6002 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
6003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
6004  AnsiString(DivergingPosition));
6005  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
6006  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
6007  int SpeedTag1 = T1.SpeedTag;
6008  int SpeedTag2 = T2.SpeedTag;
6009 
6010  if((T1.Attribute) != (T2.Attribute))
6011  {
6012  Utilities->CallLogPop(516);
6013  return(false);
6014  }
6015  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
6016  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
6017  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
6018  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
6019  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
6020  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6021  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6022  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6023  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6024  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6025  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6026  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6027  {
6028  Utilities->CallLogPop(517);
6029  return(true);
6030  }
6031  else
6032  {
6033  Utilities->CallLogPop(518);
6034  return(false);
6035  }
6036 }
6037 
6038 // ---------------------------------------------------------------------------
6039 
6040 /*
6041  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6042  {
6043  if(lower.second < higher.second) return true;
6044  else if(lower.second > higher.second) return false;
6045  else if(lower.second == higher.second)
6046  {
6047  if(lower.first < higher.first) return true;
6048  }
6049  return false;
6050  }
6051 */
6052 // ---------------------------------------------------------------------------
6053 
6054 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6055 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6056 {
6057  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6058  if(TrackElement.TrackType != GapJump)
6059  {
6060  throw Exception("Error, Wrong track type in PlotGap");
6061  }
6062  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6063  {
6064  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6065  }
6066  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6067  {
6068  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6069  }
6070  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6071  {
6072  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6073  }
6074  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6075  {
6076  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6077  }
6078  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6079  {
6080  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6081  }
6082  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6083  {
6084  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6085  }
6086  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6087  {
6088  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6089  }
6090  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6091  {
6092  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6093  }
6094  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6095  {
6096  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6097  }
6098  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6099  {
6100  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6101  }
6102  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6103  {
6104  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6105  }
6106  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6107  {
6108  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6109  }
6110  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6111  {
6112  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6113  }
6114  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6115  {
6116  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6117  }
6118  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6119  {
6120  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6121  }
6122  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6123  {
6124  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6125  }
6126  Utilities->CallLogPop(1101);
6127 }
6128 
6129 // ---------------------------------------------------------------------------
6130 
6131 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6132 {
6133  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6134  TrackElement.PlotVariableTrackElement(7, Disp);
6135  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6136  {
6137  THVPair PosPair;
6138  PosPair.first = TrackElement.HLoc;
6139  PosPair.second = TrackElement.VLoc;
6140  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6141  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6142  {
6143  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6144  }
6145  }
6146  Utilities->CallLogPop(2403);
6147 }
6148 
6149 // ---------------------------------------------------------------------------
6150 
6151 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6152 {
6153  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6154  if(TrackElement.TrackType != Points)
6155  {
6156  throw Exception("Error, Wrong track type in PlotPoints");
6157  }
6158  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6159  //check if a blue location and if so plot the blue element again - named or not as appropriate - added at v2.18.0 for blue locs at points
6160  bool FoundFlag = false;
6161  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(32, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6162  if(IMPair.first > 0) //can only have one entry in IMPair for points
6163  {
6164  TTrackElement ITE = InactiveTrackElementAt(1409, IMPair.first);
6165  if(ITE.SpeedTag == 131)
6166  {
6167  ITE.PlotVariableTrackElement(8, Disp); //plot the blue square again
6168  }
6169  }
6170  TrackElement.PlotVariableTrackElement(4, Disp);
6171  if(BothFillets)
6172  {
6173  if(TrackElement.SpeedTag < 28)
6174  {
6175  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6176  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6177  }
6178  else if(TrackElement.SpeedTag < 132)
6179  {
6180  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6181  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6182  }
6183  else
6184  {
6185  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6186  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6187  }
6188  }
6189  else if(!TrackElement.Failed) //not failed
6190  {
6191  if(TrackElement.SpeedTag < 28)
6192  {
6193  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6194  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6195  }
6196  else if(TrackElement.SpeedTag < 132)
6197  {
6198  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6199  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6200  }
6201  else
6202  {
6203  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6204  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6205  }
6206  }
6207  else //failed in fixed position
6208  {
6209  if(TrackElement.SpeedTag < 28)
6210  {
6211  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6212  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6213  }
6214  else if(TrackElement.SpeedTag < 132)
6215  {
6216  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6217  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6218  }
6219  else
6220  {
6221  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6222  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6223  }
6224  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6225  }
6226 // replot platform if required
6227  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6228  bool BlueLoc = false;
6229  if(FoundFlag)
6230  {
6231  TTrackElement TE = GetInactiveTrackElementFromTrackMap(6, TrackElement.HLoc, TrackElement.VLoc);
6232  if(TE.SpeedTag == 131) //non-station named location - don't want to replot these or the track is obscured - added at v2.18.0
6233  {
6234  BlueLoc = true;
6235  }
6236  }
6237  if(FoundFlag && !BlueLoc)
6238  {
6239  // only one platform possible at points so only need to plot IMPair.first
6240  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6241  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6242  }
6243  Utilities->CallLogPop(519);
6244 }
6245 
6246 // ---------------------------------------------------------------------------
6247 
6248 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6249 {
6250 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6252  bool FoundFlag = false;
6253  if(TrackElement.TrackType != SignalPost)
6254  {
6255  throw Exception("Error, Wrong track type in PlotSignal");
6256  }
6257  if(!TrackElement.Failed) //added at v2.13.0
6258  {
6259  for(int x = 0; x < 40; x++)
6260  {
6261  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6262  {
6263  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6264  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6265  // in case existing signal is a double yellow
6266  // plot platforms if present
6267  // Graphics::TBitmap* SignalPlatformGraphic;
6268  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6269  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6270  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6271  // to not be plotted with the above function.
6272 
6273  //replot the blue square to cover the blank area - added at v2.18.0
6274  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(36, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6275  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6276  {
6277  TTrackElement ITE = InactiveTrackElementAt(1414, IMPair.first);
6278  if(ITE.SpeedTag == 131)
6279  {
6280  ITE.PlotVariableTrackElement(9, Disp); //plot the blue square again to cover the blank area
6281  }
6282  }
6283 
6284  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6285  // now plot signal (double yellow overwrites most of signal platform if present)
6286  // additions at version 0.6 for other aspects & ground sigs
6287  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6288  {
6289  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6290  }
6291  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6292  {
6293  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6294  }
6295  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6296  {
6297  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6298  }
6299  else // 4 aspect
6300  {
6301  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6302  }
6303  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6304  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6305  {
6306  if(TrackElement.SpeedTag == 68)
6307  {
6308  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6309  }
6310  if(TrackElement.SpeedTag == 69)
6311  {
6312  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6313  }
6314  if(TrackElement.SpeedTag == 70)
6315  {
6316  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6317  }
6318  if(TrackElement.SpeedTag == 71)
6319  {
6320  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6321  }
6322  if(TrackElement.SpeedTag == 72)
6323  {
6324  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6325  }
6326  if(TrackElement.SpeedTag == 73)
6327  {
6328  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6329  }
6330  if(TrackElement.SpeedTag == 74)
6331  {
6332  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6333  }
6334  if(TrackElement.SpeedTag == 75)
6335  {
6336  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6337  }
6338  }
6339  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6340  // ground signal calling on, need to use normal proceed aspect
6341  {
6342  for(int x = 0; x < 40; x++)
6343  {
6344  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6345  {
6346  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6347  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6348  // plot special signal platform if present
6349  Graphics::TBitmap* SignalPlatformGraphic;
6350  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(37, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6351  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6352  {
6353  TTrackElement ITE = InactiveTrackElementAt(1415, IMPair.first);
6354  if(ITE.SpeedTag == 131)
6355  {
6356  ITE.PlotVariableTrackElement(10, Disp); //plot the blue square again to cover the blank area
6357  }
6358  }
6359  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6360  // now plot signal
6361  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6362  }
6363  }
6364  }
6365  break;
6366  }
6367  }
6368  }
6369  else //failed added at v2.13.0
6370  {
6371  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6372  {
6373  for(int x = 0; x < 8; x++)
6374  {
6375  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6376  {
6377  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6378  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6379  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(38, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6380  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6381  {
6382  TTrackElement ITE = InactiveTrackElementAt(1416, IMPair.first);
6383  if(ITE.SpeedTag == 131)
6384  {
6385  ITE.PlotVariableTrackElement(11, Disp); //plot the blue square again to cover the blank area
6386  }
6387  }
6388  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6389  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6390  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6391  break;
6392  }
6393  }
6394  }
6395  else
6396  {
6397  for(int x = 0; x < 8; x++)
6398  {
6399  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6400  {
6401  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6402  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6403  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(39, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6404  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6405  {
6406  TTrackElement ITE = InactiveTrackElementAt(1417, IMPair.first);
6407  if(ITE.SpeedTag == 131)
6408  {
6409  ITE.PlotVariableTrackElement(12, Disp); //plot the blue square again to cover the blank area
6410  }
6411  }
6412  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6413  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6414  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6415  break;
6416  }
6417  }
6418  }
6419  }
6420  Utilities->CallLogPop(520);
6421 }
6422 
6423 // ---------------------------------------------------------------------------
6424 
6425 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6426 {
6427  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6428  bool FoundFlag;
6429  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6430 
6431  if(!FoundFlag)
6432  {
6433  Utilities->CallLogPop(2112);
6434  return;
6435  }
6436  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6437  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6438 
6439  // don't want 'else if' for the below as may need to plot 2 platforms
6440  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6441  {
6442  if(IAElement1.LocationName == "") // '2' will be same
6443  {
6444  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6445  }
6446  else
6447  {
6448  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6449  }
6450  }
6451  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6452  {
6453  if(IAElement1.LocationName == "") // '2' will be same
6454  {
6455  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6456  }
6457  else
6458  {
6459  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6460  }
6461  }
6462  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6463  {
6464  if(IAElement1.LocationName == "") // '2' will be same
6465  {
6466  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6467  }
6468  else
6469  {
6470  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6471  }
6472  }
6473  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6474  {
6475  if(IAElement1.LocationName == "") // '2' will be same
6476  {
6477  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6478  }
6479  else
6480  {
6481  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6482  }
6483  }
6484  Utilities->CallLogPop(2113);
6485 }
6486 
6487 // ---------------------------------------------------------------------------
6488 
6489 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6490 {
6491 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6492  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6493  AnsiString(VLoc));
6494 // find topmost LC, opening them all (to trains) in turn
6495  int UpStep = 0;
6496 
6497  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6498  {
6499  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6500  UpStep--;
6501  }
6502 // now find bottommost LC, opening them all (to trains) in turn
6503  int DownStep = 1;
6504 
6505  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6506  {
6507  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6508  DownStep++;
6509  }
6510 // find leftmost LC, opening them all (to trains) in turn
6511  int LeftStep = 0;
6512 
6513  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6514  {
6515  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6516  LeftStep--;
6517  }
6518 // now find rightmost LC, opening them all (to trains) in turn
6519  int RightStep = 1;
6520 
6521  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6522  {
6523  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6524  RightStep++;
6525  }
6526  Utilities->CallLogPop(1915);
6527 }
6528 
6529 // ---------------------------------------------------------------------------
6530 
6531 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6532 {
6533  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6534 // work upwards setting all to manual
6535  int UpStep = -1;
6536 
6537  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6538  {
6539  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6540  UpStep--;
6541  }
6542 // work downwards setting all to manual
6543  int DownStep = 1;
6544 
6545  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6546  {
6547  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6548  DownStep++;
6549  }
6550 // work leftwards setting all to manual
6551  int LeftStep = -1;
6552 
6553  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6554  {
6555  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6556  LeftStep--;
6557  }
6558 // work rightwards setting all to manual
6559  int RightStep = 1;
6560 
6561  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6562  {
6563  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6564  RightStep++;
6565  }
6566  Utilities->CallLogPop(2242);
6567 }
6568 
6569 // ---------------------------------------------------------------------------
6570 
6571 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6572 {
6573  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6574  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6575  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6576  {
6577  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6578  {
6579  BarriersDownVector.at(x).TypeOfRoute = 2;
6580  break;
6581  }
6582  }
6583  Utilities->CallLogPop(2243);
6584 }
6585 
6586 // ---------------------------------------------------------------------------
6587 
6588 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6589 {
6590  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6591 // work upwards
6592  int UpStep = 0; //start with this location
6593 
6594  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6595  {
6596  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6597  {
6598  Utilities->CallLogPop(2244);
6599  return(true);
6600  }
6601  UpStep--;
6602  }
6603 // work downwards
6604  int DownStep = 1;
6605 
6606  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6607  {
6608  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6609  {
6610  Utilities->CallLogPop(2245);
6611  return(true);
6612  }
6613  DownStep++;
6614  }
6615 // work leftwards
6616  int LeftStep = -1;
6617 
6618  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6619  {
6620  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6621  {
6622  Utilities->CallLogPop(2246);
6623  return(true);
6624  }
6625  LeftStep--;
6626  }
6627 // work rightwards
6628  int RightStep = 1;
6629 
6630  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6631  {
6632  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6633  {
6634  Utilities->CallLogPop(2247);
6635  return(true);
6636  }
6637  RightStep++;
6638  }
6639  Utilities->CallLogPop(2248);
6640  return(false);
6641 }
6642 
6643 // ---------------------------------------------------------------------------
6644 
6645 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6646 {
6647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6648  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6649  {
6650  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6651  {
6652  BDVectorPos = x;
6653  Utilities->CallLogPop(2249);
6654  return(true);
6655  }
6656  }
6657  BDVectorPos = -1;
6658  Utilities->CallLogPop(2250);
6659  return(false);
6660 }
6661 
6662 // ---------------------------------------------------------------------------
6663 
6664 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6665 // open to trains
6666 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6667 {
6668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6669  AnsiString(VLoc));
6670  if(!IsLCAtHV(4, HLoc, VLoc))
6671  {
6672  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6673  }
6674  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6675  {
6676  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6677  }
6678 // check for adjacent LCs & if so open (to trains)
6679  if(BaseElementSpeedTag == 1) // hor track element
6680  {
6681  // find topmost LC, opening them all (to trains) in turn
6682  int UpStep = 0;
6683  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6684  {
6685  UpStep--;
6686  }
6687  UpStep++;
6688  // now find bottommost LC, opening them all (to trains) in turn
6689  int DownStep = 1;
6690  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6691  {
6692  DownStep++;
6693  }
6694  DownStep--;
6695  // now plot graphics, UpStep is smallest & DownStep largest
6696  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6697  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6698  Graphics::TBitmap *RouteGraphic;
6699  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6700  if(TypeOfRoute == 1)
6701  {
6702  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6703  }
6704  else if(TypeOfRoute == 0)
6705  {
6706  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6707  }
6708  else //manual - no route
6709  {
6710  RouteGraphic = BaseGraphic;
6711  }
6712 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6713 // LinkSigRouteGraphicsPtr[1] ver }
6714 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6715 // LinkNonSigRouteGraphicsPtr[1] ver }
6716 
6717  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6718  {
6719  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6720  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6721  if(!Manual)
6722  {
6723  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6724  }
6725  else
6726  {
6727  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6728  }
6729  }
6730  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6731  {
6732  if(UpStep == 0)
6733  {
6734  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6735  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6736  if(!Manual)
6737  {
6738  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6739  }
6740  else
6741  {
6742  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6743  }
6744  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6745  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6746  if(!Manual)
6747  {
6748  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6749  }
6750  else
6751  {
6752  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6753  }
6754  }
6755  else
6756  {
6757  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6758  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6759  if(!Manual)
6760  {
6761  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6762  }
6763  else
6764  {
6765  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6766  }
6767  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6768  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6769  if(!Manual)
6770  {
6771  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6772  }
6773  else
6774  {
6775  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6776  }
6777  }
6778  }
6779  else // at least one plain graphic
6780  {
6781  if(UpStep == 0)
6782  {
6783  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6784  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6785  if(!Manual)
6786  {
6787  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6788  }
6789  else
6790  {
6791  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6792  }
6793  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6794  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6795  if(!Manual)
6796  {
6797  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6798  }
6799  else
6800  {
6801  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6802  }
6803  }
6804  else if(DownStep == 0)
6805  {
6806  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6807  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6808  if(!Manual)
6809  {
6810  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6811  }
6812  else
6813  {
6814  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6815  }
6816  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6817  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6818  if(!Manual)
6819  {
6820  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6821  }
6822  else
6823  {
6824  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6825  }
6826  }
6827  else
6828  {
6829  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6830  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6831  if(!Manual)
6832  {
6833  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6834  }
6835  else
6836  {
6837  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6838  }
6839  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6840  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6841  if(!Manual)
6842  {
6843  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6844  }
6845  else
6846  {
6847  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6848  }
6849  }
6850  for(int x = (UpStep + 1); x < DownStep; x++)
6851  {
6852  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6853  if(x == 0)
6854  {
6855  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6856  }
6857  else
6858  {
6859  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6860  }
6861  if(!Manual)
6862  {
6863  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6864  }
6865  else
6866  {
6867  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6868  }
6869  }
6870  }
6871  Disp->Update();
6872  Utilities->CallLogPop(1958);
6873  return;
6874  }
6875 
6876  else // ver track element
6877  {
6878  // find leftmost LC, opening them all (to trains) in turn
6879  int LStep = 0;
6880  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6881  {
6882  LStep--;
6883  }
6884  LStep++;
6885  // now find rightmost LC, opening them all (to trains) in turn
6886  int RStep = 1;
6887  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6888  {
6889  RStep++;
6890  }
6891  RStep--;
6892  // now plot graphics, LStep is smallest & RStep largest
6893  Graphics::TBitmap *RouteGraphic;
6894  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6895  if(TypeOfRoute == 1)
6896  {
6897  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6898  }
6899  else if(TypeOfRoute == 0)
6900  {
6901  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6902  }
6903  else //manual
6904  {
6905  RouteGraphic = BaseGraphic;
6906  }
6907 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6908 // LinkSigRouteGraphicsPtr[1] ver }
6909 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6910 // LinkNonSigRouteGraphicsPtr[1] ver }
6911  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6912  {
6913  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6914  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6915  if(!Manual)
6916  {
6917  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6918  }
6919  else
6920  {
6921  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6922  }
6923  }
6924  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6925  {
6926  if(LStep == 0)
6927  {
6928  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6929  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6930  if(!Manual)
6931  {
6932  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6933  }
6934  else
6935  {
6936  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6937  }
6938  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6939  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6940  if(!Manual)
6941  {
6942  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6943  }
6944  else
6945  {
6946  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6947  }
6948  }
6949  else
6950  {
6951  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6952  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6953  if(!Manual)
6954  {
6955  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6956  }
6957  else
6958  {
6959  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6960  }
6961  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6962  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6963  if(!Manual)
6964  {
6965  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6966  }
6967  else
6968  {
6969  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6970  }
6971  }
6972  }
6973  else // at least one plain graphic
6974  {
6975  if(LStep == 0)
6976  {
6977  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6978  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6979  if(!Manual)
6980  {
6981  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6982  }
6983  else
6984  {
6985  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6986  }
6987  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6988  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6989  if(!Manual)
6990  {
6991  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6992  }
6993  else
6994  {
6995  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6996  }
6997  }
6998  else if(RStep == 0)
6999  {
7000  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7001  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7002  if(!Manual)
7003  {
7004  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7005  }
7006  else
7007  {
7008  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7009  }
7010  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7011  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
7012  if(!Manual)
7013  {
7014  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7015  }
7016  else
7017  {
7018  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7019  }
7020  }
7021  else
7022  {
7023  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7024  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7025  if(!Manual)
7026  {
7027  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7028  }
7029  else
7030  {
7031  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7032  }
7033  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7034  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7035  if(!Manual)
7036  {
7037  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7038  }
7039  else
7040  {
7041  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7042  }
7043  }
7044  for(int x = (LStep + 1); x < RStep; x++)
7045  {
7046  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7047  if(x == 0)
7048  {
7049  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
7050  }
7051  else
7052  {
7053  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
7054  }
7055  if(!Manual)
7056  {
7057  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7058  }
7059  else
7060  {
7061  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7062  }
7063  }
7064  }
7065  Disp->Update();
7066  Utilities->CallLogPop(1896);
7067  return;
7068  }
7069 }
7070 
7071 // ---------------------------------------------------------------------------
7072 
7073 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
7074 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7075 {
7076  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
7077  AnsiString(HLoc) + "," + AnsiString(VLoc));
7078  if(!IsLCAtHV(29, HLoc, VLoc))
7079  {
7080  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7081  }
7082  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7083  {
7084  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7085  }
7086 // check for adjacent LCs & if so open (to trains)
7087  if(BaseElementSpeedTag == 1) // hor track element
7088  {
7089  // find topmost LC, opening them all (to trains) in turn
7090  int UpStep = 0;
7091  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7092  {
7093  UpStep--;
7094  }
7095  UpStep++;
7096  // now find bottommost LC, opening them all (to trains) in turn
7097  int DownStep = 1;
7098  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7099  {
7100  DownStep++;
7101  }
7102  DownStep--;
7103  // now plot graphics, UpStep is smallest & DownStep largest
7104  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7105  {
7106  if(!Manual)
7107  {
7108  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7109  }
7110  else
7111  {
7112  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7113  }
7114  }
7115  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7116  {
7117  if(!Manual)
7118  {
7119  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7120  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7121  }
7122  else
7123  {
7124  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7125  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7126  }
7127  }
7128  else // at least one plain graphic
7129  {
7130  if(!Manual)
7131  {
7132  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7133  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7134  for(int x = (UpStep + 1); x < DownStep; x++)
7135  {
7136  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7137  }
7138  }
7139  else
7140  {
7141  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7142  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7143  for(int x = (UpStep + 1); x < DownStep; x++)
7144  {
7145  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7146  }
7147  }
7148  }
7149  // set markers
7150  for(int x = UpStep; x <= DownStep; x++)
7151  {
7152  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7153  }
7154  Display->Update();
7155  Utilities->CallLogPop(1944);
7156  return;
7157  }
7158 
7159  else // ver track element
7160  {
7161  // find leftmost LC, opening them all (to trains) in turn
7162  int LStep = 0;
7163  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7164  {
7165  LStep--;
7166  }
7167  LStep++;
7168  // now find rightmost LC, opening them all (to trains) in turn
7169  int RStep = 1;
7170  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7171  {
7172  RStep++;
7173  }
7174  RStep--;
7175  // now plot graphics, LStep is smallest & RStep largest
7176  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7177  {
7178  if(!Manual)
7179  {
7180  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7181  }
7182  else
7183  {
7184  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7185  }
7186  }
7187  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7188  {
7189  if(!Manual)
7190  {
7191  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7192  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7193  }
7194  else
7195  {
7196  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7197  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7198  }
7199  }
7200  else // at least one plain graphic
7201  {
7202  if(!Manual)
7203  {
7204  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7205  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7206  for(int x = (LStep + 1); x < RStep; x++)
7207  {
7208  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7209  }
7210  }
7211  else
7212  {
7213  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7214  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7215  for(int x = (LStep + 1); x < RStep; x++)
7216  {
7217  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7218  }
7219  }
7220  }
7221  // set markers
7222  for(int x = LStep; x <= RStep; x++)
7223  {
7224  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7225  }
7226  Disp->Update();
7227  Utilities->CallLogPop(1945);
7228  return;
7229  }
7230 }
7231 
7232 // ---------------------------------------------------------------------------
7233 
7234 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7235 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7236 {
7237  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7238  AnsiString(VLoc));
7239  if(!IsLCAtHV(9, HLoc, VLoc))
7240  {
7241  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7242  }
7243  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7244  {
7245  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7246  }
7247 // check for adjacent LCs & if so close (to trains)
7248  if(BaseElementSpeedTag == 1) // hor track element
7249  {
7250  // find topmost LC, closing them all (to trains) in turn
7251  int UpStep = 0;
7252  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7253  {
7254  UpStep--;
7255  }
7256  UpStep++;
7257  // now find bottommost LC, opening them all (to trains) in turn
7258  int DownStep = 1;
7259  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7260  {
7261  DownStep++;
7262  }
7263  DownStep--;
7264  // now plot graphics, UpStep is smallest & DownStep largest
7265  for(int x = UpStep; x < (DownStep + 1); x++)
7266  {
7267  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7268  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7269  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7270  }
7271  Disp->Update();
7272  Utilities->CallLogPop(1959);
7273  return;
7274  }
7275 
7276  else // ver track element
7277  {
7278  // find leftmost LC, closing them all (to trains) in turn
7279  int LStep = 0;
7280  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7281  {
7282  LStep--;
7283  }
7284  LStep++;
7285  // now find rightmost LC, opening them all (to trains) in turn
7286  int RStep = 1;
7287  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7288  {
7289  RStep++;
7290  }
7291  RStep--;
7292  // now plot graphics, LStep is smallest & RStep largest
7293  for(int x = LStep; x < (RStep + 1); x++)
7294  {
7295  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7296  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7297  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7298  }
7299  Disp->Update();
7300  Utilities->CallLogPop(1960);
7301  return;
7302  }
7303 }
7304 
7305 // ---------------------------------------------------------------------------
7306 
7307 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7308 // closed to trains
7309 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7310 {
7311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7312  AnsiString(HLoc) + "," + AnsiString(VLoc));
7313  if(!IsLCAtHV(34, HLoc, VLoc))
7314  {
7315  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7316  }
7317  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7318  {
7319  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7320  }
7321  TTrackElement TE;
7322 
7323 // check for adjacent LCs & if so close (to trains)
7324  if(BaseElementSpeedTag == 1) // hor track element
7325  {
7326  // find topmost LC, closing them all (to trains) in turn
7327  int UpStep = 0;
7328  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7329  {
7330  UpStep--;
7331  }
7332  UpStep++;
7333  // now find bottommost LC, opening them all (to trains) in turn
7334  int DownStep = 1;
7335  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7336  {
7337  DownStep++;
7338  }
7339  DownStep--;
7340  // now plot graphics, UpStep is smallest & DownStep largest
7341  for(int x = UpStep; x <= DownStep; x++)
7342  {
7343  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7344  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7345  }
7346  Display->Update();
7347  Utilities->CallLogPop(1946);
7348  return;
7349  }
7350 
7351  else // ver track element
7352  {
7353  // find leftmost LC, closing them all (to trains) in turn
7354  int LStep = 0;
7355  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7356  {
7357  LStep--;
7358  }
7359  LStep++;
7360  // now find rightmost LC, opening them all (to trains) in turn
7361  int RStep = 1;
7362  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7363  {
7364  RStep++;
7365  }
7366  RStep--;
7367  // now plot graphics, LStep is smallest & RStep largest
7368  for(int x = LStep; x <= RStep; x++)
7369  {
7370  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7371  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7372  }
7373  Display->Update();
7374  Utilities->CallLogPop(1947);
7375  return;
7376  }
7377 }
7378 
7379 // ---------------------------------------------------------------------------
7380 
7381 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7382 {
7383  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7384  Graphics::TBitmap *RouteGraphic;
7385  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7386 
7387  if(BaseElementSpeedTag == 1)
7388  {
7389  if(TypeOfRoute == 1)
7390  {
7391  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7392  }
7393  else if(TypeOfRoute == 0)
7394  {
7395  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7396  }
7397  else //manual
7398  {
7399  RouteGraphic = BaseGraphic;
7400  }
7401  if(State == Raising)
7402  {
7403  RouteGraphic = BaseGraphic;
7404  }
7405  }
7406  else
7407  {
7408  BaseGraphic = RailGraphics->gl2;
7409  if(TypeOfRoute == 1)
7410  {
7411  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7412  }
7413  else if(TypeOfRoute == 0)
7414  {
7415  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7416  }
7417  else
7418  {
7419  RouteGraphic = BaseGraphic; //manual
7420  }
7421  if(State == Raising)
7422  {
7423  RouteGraphic = BaseGraphic;
7424  }
7425  }
7426  int UpStep = 0;
7427 
7428  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7429  {
7430  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7431  if(UpStep == 0)
7432  {
7433  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7434  }
7435  else
7436  {
7437  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7438  }
7439  UpStep--;
7440  }
7441 // now find bottommost LC, opening them all (to trains) in turn
7442  int DownStep = 1;
7443 
7444  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7445  {
7446  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7447  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7448  DownStep++;
7449  }
7450  int LeftStep = 0;
7451 
7452  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7453  {
7454  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7455  if(LeftStep == 0)
7456  {
7457  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7458  }
7459  else
7460  {
7461  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7462  }
7463  LeftStep--;
7464  }
7465 // now find rightmost LC, opening them all (to trains) in turn
7466  int RightStep = 1;
7467 
7468  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7469  {
7470  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7471  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7472  RightStep++;
7473  }
7474  Disp->Update();
7475  Utilities->CallLogPop(1914);
7476 }
7477 
7478 // ---------------------------------------------------------------------------
7479 
7480 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7481 {
7482 // return false for no LC there, flashing or a closed (to trains) LC
7483  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7484  bool FoundFlag;
7485  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7486 
7487  if(!FoundFlag)
7488  {
7489  Utilities->CallLogPop(1898);
7490  return(false);
7491  }
7492  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7493  {
7494  Utilities->CallLogPop(1899);
7495  return(false);
7496  }
7497  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7498  {
7499  Utilities->CallLogPop(1900);
7500  return(true);
7501  }
7502  Utilities->CallLogPop(1901);
7503  return(false);
7504 }
7505 
7506 // ---------------------------------------------------------------------------
7507 
7508 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7509 {
7510 // return false for no LC there, flashing LC or open (to trains) LC
7511  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7512  bool FoundFlag;
7513  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7514 
7515  if(!FoundFlag)
7516  {
7517  Utilities->CallLogPop(1922);
7518  return(false);
7519  }
7520  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7521  {
7522  Utilities->CallLogPop(1923);
7523  return(false);
7524  }
7525  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7526  {
7527  Utilities->CallLogPop(1924);
7528  return(true);
7529  }
7530  Utilities->CallLogPop(1925);
7531  return(false);
7532 }
7533 
7534 // ---------------------------------------------------------------------------
7535 
7536 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7537 {
7538 // return true for barrier in process of moving
7539  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7540  bool FoundFlag;
7541  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7542 
7543  if(!FoundFlag)
7544  {
7545  Utilities->CallLogPop(1918);
7546  return(false);
7547  }
7548  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7549  {
7550  Utilities->CallLogPop(1919);
7551  return(false);
7552  }
7553  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7554  {
7555  Utilities->CallLogPop(1920);
7556  return(true);
7557  }
7558  Utilities->CallLogPop(1921);
7559  return(false);
7560 }
7561 
7562 // ---------------------------------------------------------------------------
7563 
7564 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7565 {
7566 // return true for an LC at H&V
7567  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7568  bool FoundFlag;
7569  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7570 
7571  if(!FoundFlag)
7572  {
7573  Utilities->CallLogPop(1902);
7574  return(false);
7575  }
7576  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7577  {
7578  Utilities->CallLogPop(1903);
7579  return(false);
7580  }
7581  Utilities->CallLogPop(1904);
7582  return(true);
7583 }
7584 
7585 // ---------------------------------------------------------------------------
7586 
7587 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7588 {
7589  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7590  AnsiString(Attr));
7591  bool FoundFlag;
7592  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7593 
7594  if(!FoundFlag)
7595  {
7596  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7597  }
7598  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7599  {
7600  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7601  }
7602  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7603  Utilities->CallLogPop(1905);
7604  return;
7605 }
7606 
7607 // ---------------------------------------------------------------------------
7608 
7610 {
7611  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7612  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7613  {
7614  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7615  if(InactiveTrackElement.TrackType == LevelCrossing)
7616  {
7617  InactiveTrackElementAt(141, x).Attribute = 0;
7618  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7619  }
7620  }
7621  Utilities->CallLogPop(1913);
7622  return;
7623 }
7624 
7625 // ---------------------------------------------------------------------------
7626 
7627 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7628 {
7629 // return true if there is either a route set or being set on any element or a train on any element
7630  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7631  "," + AnsiString(VLoc));
7632 
7633  THVPair TrackMapKeyPair;
7634  TTrack::TTrackMapIterator TrackMapPtr;
7635  int DummyRouteNumber;
7636 
7637  TrainPresent = false;
7638 // find topmost LC, checking each for routes & trains
7639  int UpStep = 0;
7640 
7641  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7642  {
7643  TrackMapKeyPair.first = HLoc;
7644  TrackMapKeyPair.second = VLoc + UpStep;
7645  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7646  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7647  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7648  {
7649  Utilities->CallLogPop(1932);
7650  return(true);
7651  }
7652  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7653  {
7654  TrainPresent = true;
7655  Utilities->CallLogPop(1933);
7656  return(true);
7657  }
7658  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7659  {
7660  Utilities->CallLogPop(2274);
7661  return(true);
7662  }
7663  UpStep--;
7664  }
7665 // now find bottommost LC, opening them all (to trains) in turn
7666  int DownStep = 1;
7667 
7668  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7669  {
7670  TrackMapKeyPair.first = HLoc;
7671  TrackMapKeyPair.second = VLoc + DownStep;
7672  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7673  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7674  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7675  {
7676  Utilities->CallLogPop(1934);
7677  return(true);
7678  }
7679  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7680  {
7681  TrainPresent = true;
7682  Utilities->CallLogPop(1935);
7683  return(true);
7684  }
7685  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7686  {
7687  Utilities->CallLogPop(2275);
7688  return(true);
7689  }
7690  DownStep++;
7691  }
7692 // find leftmost LC
7693  int LeftStep = 0;
7694 
7695  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7696  {
7697  TrackMapKeyPair.first = HLoc + LeftStep;
7698  TrackMapKeyPair.second = VLoc;
7699  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7700  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7701  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7702  {
7703  Utilities->CallLogPop(1936);
7704  return(true);
7705  }
7706  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7707  {
7708  TrainPresent = true;
7709  Utilities->CallLogPop(1937);
7710  return(true);
7711  }
7712  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7713  {
7714  Utilities->CallLogPop(2276);
7715  return(true);
7716  }
7717  LeftStep--;
7718  }
7719 // now find rightmost LC, opening them all (to trains) in turn
7720  int RightStep = 1;
7721 
7722  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7723  {
7724  TrackMapKeyPair.first = HLoc + RightStep;
7725  TrackMapKeyPair.second = VLoc;
7726  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7727  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7728  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7729  {
7730  Utilities->CallLogPop(1938);
7731  return(true);
7732  }
7733  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7734  {
7735  TrainPresent = true;
7736  Utilities->CallLogPop(1939);
7737  return(true);
7738  }
7739  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7740  {
7741  Utilities->CallLogPop(2277);
7742  return(true);
7743  }
7744  RightStep++;
7745  }
7746  Utilities->CallLogPop(1940);
7747  return(false);
7748 }
7749 
7750 // ---------------------------------------------------------------------------
7751 
7752 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7753 {
7754  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7755  for(unsigned int x = 0; x < SearchVector.size(); x++)
7756  {
7757  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7758  {
7759  Utilities->CallLogPop(2278);
7760  return(true);
7761  }
7762  }
7763  Utilities->CallLogPop(2279);
7764  return(false);
7765 }
7766 
7767 // ---------------------------------------------------------------------------
7768 
7769 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7770 {
7771  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7772  AnsiString(HLoc) + "," + AnsiString(VLoc));
7773  if(!IsLCAtHV(60, HLoc, VLoc))
7774  {
7775  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7776  }
7777 
7778 // check for adjacent LCs
7779  // find topmost LC
7780  int UpStep = 0;
7781  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7782  {
7783  UpStep--;
7784  }
7785  UpStep++;
7786  // now find bottommost LC, opening them all (to trains) in turn
7787  int DownStep = 1;
7788  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7789  {
7790  DownStep++;
7791  }
7792  DownStep--;
7793  // now plot graphics, UpStep is smallest & DownStep largest
7794  for(int x = UpStep; x <= DownStep; x++)
7795  {
7796  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7797  }
7798 
7799  // find leftmost LC, closing them all (to trains) in turn
7800  int LStep = 0;
7801  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7802  {
7803  LStep--;
7804  }
7805  LStep++;
7806  // now find rightmost LC, opening them all (to trains) in turn
7807  int RStep = 1;
7808  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7809  {
7810  RStep++;
7811  }
7812  RStep--;
7813  // now plot graphics, LStep is smallest & RStep largest
7814  for(int x = LStep; x <= RStep; x++)
7815  {
7816  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7817  }
7818  Display->Update();
7819  Utilities->CallLogPop(2315);
7820  return;
7821 }
7822 
7823 // ---------------------------------------------------------------------------
7824 
7825 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7826 {
7827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7828  if(TrackElement.TrackType != Points)
7829  {
7830  throw Exception("Error, Wrong track type in GetFilletGraphic");
7831  }
7832  if(TrackElement.SpeedTag < 28)
7833  {
7834  Utilities->CallLogPop(521);
7835  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7836  }
7837  else if(TrackElement.SpeedTag < 132)
7838  {
7839  Utilities->CallLogPop(522);
7840 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7841  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7842  }
7843  else
7844  {
7845  Utilities->CallLogPop(1537);
7846  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7847  }
7848 }
7849 
7850 // ---------------------------------------------------------------------------
7851 
7853 {
7854  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7855  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7856  {
7857  TrackElementAt(1351, x).TrainIDOnElement = -1;
7860  }
7861  Utilities->CallLogPop(1342);
7862 }
7863 
7864 // ---------------------------------------------------------------------------
7865 
7866 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7867 /*
7868  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7869 */
7870 {
7871  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7872  AnsiString(ScreenPosV));
7873  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7874  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7875 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7876  Utilities->CallLogPop(535);
7877 }
7878 
7879 // ---------------------------------------------------------------------------
7880 
7881 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7882 /*
7883  Converts the screen position to the true (without offsets) position
7884 */
7885 {
7886  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7887  AnsiString(ScreenPosV));
7888  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7889  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7890  Utilities->CallLogPop(536);
7891 }
7892 
7893 // ---------------------------------------------------------------------------
7894 
7895 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7896 {
7897  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7898  AnsiString(VPosTrue));
7899  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7900  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7901  Utilities->CallLogPop(537);
7902 }
7903 
7904 // ---------------------------------------------------------------------------
7905 
7906 void TTrack::CheckMapAndTrack(int Caller) // test
7907 {
7908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7909  int Zeroes = 0;
7910  bool FoundFlag;
7911 
7912  for(unsigned int a = 0; a < TrackVector.size(); a++)
7913  {
7914  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7915  if(CheckElement.SpeedTag == 0)
7916  {
7917  Zeroes++; // zeroed elements not saved in map
7918  }
7919  else
7920  {
7921  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7922  if(!FoundFlag)
7923  {
7924  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7925  " in TrackMap, Caller=" + (AnsiString)Caller);
7926  }
7927  if(MapVecPos != (int)a)
7928  {
7929  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7930  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7931  (AnsiString)Caller);
7932  }
7933  }
7934  }
7935  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7936  {
7937  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7938  " Caller=" + (AnsiString)Caller);
7939  }
7940  Utilities->CallLogPop(538);
7941  return;
7942 }
7943 
7944 // ---------------------------------------------------------------------------
7945 
7946 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7947 {
7948  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7949  bool FoundFlag;
7950  TIMPair InactivePair;
7951 
7952  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7953  {
7954  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7955  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7956  if(!FoundFlag)
7957  {
7958  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7959  " in InactiveMap, Caller=" + (AnsiString)Caller);
7960  }
7961  if((InactivePair.first != a) && (InactivePair.second != a))
7962  {
7963  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7964  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7965  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7966  }
7967  }
7968  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7969  {
7970  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7971  " Caller=" + (AnsiString)Caller);
7972  }
7973  Utilities->CallLogPop(539);
7974 }
7975 
7976 // ---------------------------------------------------------------------------
7977 
7978 void TTrack::CheckGapMap(int Caller) // test
7979 {
7980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7981  int Position1, Position2;
7982  TTrackElement TrackElement1, TrackElement2;
7983  TGapMapIterator GapMapPtr;
7984 
7985  if(!GapMap.empty())
7986  {
7987  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7988  {
7989  int HLoc1 = GapMapPtr->first.first;
7990  int VLoc1 = GapMapPtr->first.second;
7991  int HLoc2 = GapMapPtr->second.first;
7992  int VLoc2 = GapMapPtr->second.second;
7993  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7994  {
7995  throw Exception("Failed to find H & V for gap1, GapMap in error");
7996  }
7997  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7998  {
7999  throw Exception("Failed to find H & V for gap2, GapMap in error");
8000  }
8001  if(TrackElementAt(17, Position1).TrackType != GapJump)
8002  {
8003  throw Exception("Element at Pos1 not a gap, GapMap in error");
8004  }
8005  if(TrackElementAt(18, Position2).TrackType != GapJump)
8006  {
8007  throw Exception("Element at Pos2 not a gap, GapMap in error");
8008  }
8009  }
8010  }
8011  unsigned int GapCount = 0;
8012 
8013  for(unsigned int a = 0; a < TrackVector.size(); a++)
8014  {
8015  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
8016  if(CheckElement.TrackType == GapJump)
8017  {
8018  GapCount++;
8019  }
8020  }
8021  if((GapMap.size() * 2) != GapCount)
8022  {
8023  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
8024  (AnsiString)Caller);
8025  }
8026  Utilities->CallLogPop(540);
8027 }
8028 
8029 // ---------------------------------------------------------------------------
8030 
8031 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
8032 {
8033  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
8034  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
8035  {
8036  if(TrackFinished)
8037  {
8038  throw Exception("Error - TrackFinished with erase element still present");
8039  }
8040  Utilities->CallLogPop(541);
8041  return; // erased element, can't set ID
8042  }
8043  AnsiString IDString;
8044 
8045  if(TrackElement.HLoc < 0)
8046  {
8047  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
8048  }
8049  else
8050  {
8051  IDString = AnsiString(TrackElement.HLoc) + "-";
8052  }
8053  if(TrackElement.VLoc < 0)
8054  {
8055  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
8056  }
8057  else
8058  {
8059  IDString += AnsiString(TrackElement.VLoc);
8060  }
8061  TrackElement.ElementID = IDString;
8062  Utilities->CallLogPop(542);
8063 }
8064 
8065 // ---------------------------------------------------------------------------
8066 
8067 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
8068 {
8069 // e.g. "8-13", "00008-13", "N43-N127", etc
8070  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
8071  int DelimPos;
8072 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
8073  {
8074  for(int x = 1; x < String.Length() + 1; x++)
8075  {
8076  if(String.IsDelimiter("-", x))
8077  {
8078  DelimPos = x;
8079  break;
8080  }
8081  if(x == String.Length())
8082  {
8083  if(GiveMessages)
8084  {
8085  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8086  }
8087  Utilities->CallLogPop(543);
8088  return(-1);
8089  }
8090  }
8091  if(DelimPos == 1)
8092  {
8093  if(GiveMessages)
8094  {
8095  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8096  }
8097  Utilities->CallLogPop(544);
8098  return(-1);
8099  }
8100  if(DelimPos == String.Length())
8101  {
8102  if(GiveMessages)
8103  {
8104  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8105  }
8106  Utilities->CallLogPop(545);
8107  return(-1);
8108  }
8109  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8110  {
8111  if(GiveMessages)
8112  {
8113  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8114  }
8115  Utilities->CallLogPop(1508);
8116  return(-1);
8117  }
8118  int HLoc, VLoc;
8119 
8120  if(String.SubString(1, 1) != "N")
8121  {
8122  for(int x = 1; x < DelimPos; x++)
8123  {
8124  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8125  {
8126  if(GiveMessages)
8127  {
8128  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8129  }
8130  Utilities->CallLogPop(546);
8131  return(-1);
8132  }
8133  }
8134  }
8135  if(String.SubString(1, 1) == "N")
8136  {
8137  for(int x = 2; x < DelimPos; x++)
8138  {
8139  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8140  {
8141  if(GiveMessages)
8142  {
8143  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8144  }
8145  Utilities->CallLogPop(763);
8146  return(-1);
8147  }
8148  }
8149  }
8150  if(String.SubString(1, 1) == "N")
8151  {
8152  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8153  }
8154  else
8155  {
8156  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8157  }
8158  if(String.SubString(DelimPos + 1, 1) != "N")
8159  {
8160  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8161  {
8162  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8163  {
8164  if(GiveMessages)
8165  {
8166  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8167  }
8168  Utilities->CallLogPop(547);
8169  return(-1);
8170  }
8171  }
8172  }
8173  if(String.SubString(DelimPos + 1, 1) == "N")
8174  {
8175  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8176  {
8177  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8178  {
8179  if(GiveMessages)
8180  {
8181  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8182  }
8183  Utilities->CallLogPop(764);
8184  return(-1);
8185  }
8186  }
8187  }
8188  if(String.SubString(DelimPos + 1, 1) == "N")
8189  {
8190  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8191  }
8192  else
8193  {
8194  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8195  }
8196  THVPair HVPair(HLoc, VLoc);
8197  TTrackMapIterator TrackMapPtr;
8198 
8199  TrackMapPtr = TrackMap.find(HVPair);
8200  if(TrackMapPtr == TrackMap.end())
8201  {
8202  if(GiveMessages)
8203  {
8204  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8205  }
8206  Utilities->CallLogPop(548);
8207  return(-1);
8208  }
8209  Utilities->CallLogPop(549);
8210  return(TrackMapPtr->second);
8211  }
8212  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8213  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8214  {
8215  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8216  Utilities->CallLogPop(2481);
8217  return(-1);
8218  }
8219 }
8220 
8221 // ---------------------------------------------------------------------------
8222 
8223 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8224 /*
8225  True for linked properly at both ends
8226 */
8227 {
8228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8229  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8230  int HLoc = TrackElement.HLoc;
8231  int VLoc = TrackElement.VLoc;
8232 
8233  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8234  {
8235  Utilities->CallLogPop(1821);
8236  return(false);
8237  }
8238  if(TrackElement.SpeedTag == 129) // vertical footbridge
8239  {
8240  // check top connection
8241  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8242  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8243  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8244  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8245  {
8246  Utilities->CallLogPop(550);
8247  return(false);
8248  }
8249  // check bottom connection
8250  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8251  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8252  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8253  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8254  {
8255  Utilities->CallLogPop(551);
8256  return(false);
8257  }
8258  }
8259  if(TrackElement.SpeedTag == 145) // vertical underpass
8260  {
8261  // check top connection
8262  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8263  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8264  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8265  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8266  {
8267  Utilities->CallLogPop(2114);
8268  return(false);
8269  }
8270  // check bottom connection
8271  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8272  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8273  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8274  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8275  {
8276  Utilities->CallLogPop(2115);
8277  return(false);
8278  }
8279  }
8280  if(TrackElement.SpeedTag == 130) // hor footbridge
8281  {
8282  // check left connection
8283  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8284  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8285  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8286  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8287  {
8288  Utilities->CallLogPop(552);
8289  return(false);
8290  }
8291  // check right connection
8292  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8293  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8294  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8295  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8296  {
8297  Utilities->CallLogPop(553);
8298  return(false);
8299  }
8300  }
8301  if(TrackElement.SpeedTag == 146) // hor u'pass
8302  {
8303  // check left connection
8304  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8305  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8306  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8307  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8308  {
8309  Utilities->CallLogPop(2116);
8310  return(false);
8311  }
8312  // check right connection
8313  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8314  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8315  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8316  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8317  {
8318  Utilities->CallLogPop(2117);
8319  return(false);
8320  }
8321  }
8322  Utilities->CallLogPop(554);
8323  return(true);
8324 }
8325 
8326 // ---------------------------------------------------------------------------
8327 
8328 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8329 /*
8330  return true if the SpeedTag present in the map at H & V
8331 */
8332 {
8333  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8334  AnsiString(SpeedTag));
8335  if(InactiveTrack2MultiMap.empty())
8336  {
8337  Utilities->CallLogPop(555);
8338  return(false);
8339  }
8340  THVPair HVPair(HLoc, VLoc);
8342  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8343  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8344 
8345  if(HVRange.first == HVRange.second)
8346  {
8347  Utilities->CallLogPop(556);
8348  return(false);
8349  }
8350  else
8351  {
8352  HVIt1 = HVRange.first;
8353  }
8354  TTrackElement Temp1, Temp2; // test
8355 
8356  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8357  if(--HVRange.second != HVRange.first)
8358  {
8359  HVIt2 = HVRange.second;
8360  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8361  }
8362  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8363  HVIt2->second).SpeedTag == SpeedTag)))
8364  {
8365  Utilities->CallLogPop(557);
8366  return(true);
8367  }
8368  else
8369  {
8370  Utilities->CallLogPop(558);
8371  return(false);
8372  }
8373 }
8374 
8375 // ---------------------------------------------------------------------------
8376 
8377 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8378 /*
8379  return true if the SpeedTag present in the map at H & V
8380 */
8381 {
8382  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8383  AnsiString(SpeedTag));
8384  if(TrackMap.empty())
8385  {
8386  Utilities->CallLogPop(559);
8387  return(false);
8388  }
8389  THVPair HVPair(HLoc, VLoc);
8390  TTrackMapIterator End = TrackMap.end();
8391  TTrackMapIterator It = End;
8392 
8393  It = TrackMap.find(HVPair);
8394  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8395  {
8396  Utilities->CallLogPop(560);
8397  return(true);
8398  }
8399  else
8400  {
8401  Utilities->CallLogPop(561);
8402  return(false);
8403  }
8404 }
8405 
8406 // ---------------------------------------------------------------------------
8407 
8408 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8409 {
8410 /*
8411  General:
8412  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8413  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8414  a NamedNonStationLocation.
8415  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8416  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8417  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8418  platform at that location).
8419 
8420  Linked named location elements are those explained in TTrack::TTrack()
8421 
8422  Detail:
8423  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8424  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8425  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8426  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8427  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8428  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8429 
8430  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8431  this function a single element should be in the List (normally from the user's selection but can also be from
8432  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8433  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8434  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8435  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8436  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8437  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8438  moves them into the Map. At the end all linked elements are in the Map.
8439 
8440  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8441  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8442  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8443 */
8444 
8445 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8446 // Display->FileDiagnostics(TestString);//test
8447 
8448  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8449  AnsiString TestString1, TestString2; // test
8450 
8451  Track->LNDone2MultiMap.clear();
8452  if(LNPendingList.size() != 1)
8453  {
8454  throw Exception("LNPendingList size not 1 on entry");
8455  }
8456  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8457  bool FoundFlag = false, ErasedFlag = false;
8458  while(!LNPendingList.empty())
8459  {
8460  CurrentElementNumber = LNPendingList.front();
8461  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8462  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8463  int H = CurrentElement->HLoc;
8464  int V = CurrentElement->VLoc;
8465  int Tag = CurrentElement->SpeedTag;
8466  if(Tag == 76) // top plat
8467  {
8468  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8469  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8470  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8471  for(int x = 0; x < 25; x++)
8472  {
8473  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8474  {
8475  LNPendingList.insert(LNPendingList.end(), NewElement);
8476  }
8477  }
8478  }
8479  else if(Tag == 77) // bot plat
8480  {
8481  for(int x = 0; x < 25; x++)
8482  {
8483  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8484  {
8485  LNPendingList.insert(LNPendingList.end(), NewElement);
8486  }
8487  }
8488  }
8489  else if(Tag == 78) // l plat
8490  {
8491  for(int x = 0; x < 25; x++)
8492  {
8493  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8494  {
8495  LNPendingList.insert(LNPendingList.end(), NewElement);
8496  }
8497  }
8498  }
8499  else if(Tag == 79) // r plat
8500  {
8501  for(int x = 0; x < 25; x++)
8502  {
8503  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8504  {
8505  LNPendingList.insert(LNPendingList.end(), NewElement);
8506  }
8507  }
8508  }
8509  else if(Tag == 96) // conc
8510  {
8511  for(int x = 0; x < 28; x++)
8512  {
8513  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8514  {
8515  LNPendingList.insert(LNPendingList.end(), NewElement);
8516  }
8517  }
8518  }
8519  else if(Tag == 129) // vert footbridge
8520  {
8521  for(int x = 0; x < 8; x++)
8522  {
8523  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8524  {
8525  LNPendingList.insert(LNPendingList.end(), NewElement);
8526  }
8527  }
8528  }
8529  else if(Tag == 130) // hor footbridge
8530  {
8531  for(int x = 0; x < 8; x++)
8532  {
8533  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8534  {
8535  LNPendingList.insert(LNPendingList.end(), NewElement);
8536  }
8537  }
8538  }
8539  else if(Tag == 131) // named location
8540  {
8541  for(int x = 0; x < 4; x++)
8542  {
8543  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8544  {
8545  LNPendingList.insert(LNPendingList.end(), NewElement);
8546  }
8547  }
8548  int TVPos = GetVectorPositionFromTrackMap(67, H, V, FoundFlag); //deal with gaps, added at v2.18.0
8549  {
8550  if(FoundFlag && TrackElementAt(1585, TVPos).TrackType == GapJump)
8551  {
8552  int GJTVPos = TrackElementAt(1586, TVPos).Conn[0];
8553  if(GJTVPos > -1)
8554  {
8555  int HLoc = TrackElementAt(1587, GJTVPos).HLoc;
8556  int VLoc = TrackElementAt(1588, GJTVPos).VLoc;
8557  bool FoundFlag2 = false;
8558  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(33, HLoc, VLoc, FoundFlag2);
8559  if(FoundFlag2)
8560  {
8561  if(Track->InactiveTrackElementAt(1410, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
8562  {
8563  if(!ElementInLNDone2MultiMap(5, IMPair.first) && !ElementInLNPendingList(6, IMPair.first))
8564  {
8565  LNPendingList.insert(LNPendingList.end(), IMPair.first);
8566  }
8567  }
8568  }
8569  }
8570  }
8571  }
8572  }
8573  else if(Tag == 145) // v u'pass
8574  {
8575  for(int x = 0; x < 8; x++)
8576  {
8577  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8578  {
8579  LNPendingList.insert(LNPendingList.end(), NewElement);
8580  }
8581  }
8582  }
8583  else if(Tag == 146) // h u'pass
8584  {
8585  for(int x = 0; x < 8; x++)
8586  {
8587  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8588  {
8589  LNPendingList.insert(LNPendingList.end(), NewElement);
8590  }
8591  }
8592  }
8593  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8594 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8595  if(AddingElements)
8596  {
8597  int HPos, VPos; // not used but needed for FindText function
8598  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8599  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8600  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8601  {
8602  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8603  if((ExistingName != "") && (ExistingName != LocationName))
8604  {
8605  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8606  {
8607  } // name not in LocationNameMultiMap, so don't erase from TextVector
8608  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8609  {
8610  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8611  {
8612  ;
8613  } // condition not used
8614 
8615  }
8616  }
8617  }
8618  }
8619  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8620  // track at that loc
8621  THVPair HVPair(H, V);
8622  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8623  LNDone2MultiMapEntry.first = HVPair;
8624  LNDone2MultiMapEntry.second = LNPendingList.front();
8625  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8626  LNPendingList.erase(LNPendingList.begin());
8627  }
8628 
8629 // search all name multimap for same name where corresponding active elements don't appear in
8630 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8631 
8632  TLocationNameMultiMapIterator SNIterator;
8633  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8634 
8635  if(SNRange.first != SNRange.second)
8636  {
8637  SNRange.first--; // now pointing to before the first
8638  SNRange.second--; // now pointing to the last
8639  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8640  {
8641  // Same elements are in Done map as in name map
8642  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8643  {
8644  ErasedFlag = true;
8645  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8646  TVIt->LocationName = "";
8647  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8648  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8649  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8650  {
8651  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8652  if(FoundFlag)
8653  {
8654  TrackElementAt(20, Position).LocationName = "";
8655  TrackElementAt(21, Position).ActiveTrackElementName = "";
8656  }
8657  }
8658  // erase name in name map
8659 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8660  }
8661  }
8662  }
8663  if(ErasedFlag)
8664  {
8666  }
8667  if(TrackFinished)
8668  {
8671  }
8672 // set here as well as in LinkTrack so don't have to link track just because a name added
8673 // if track not finished then will be set when track validated
8674 
8675 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8676 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8677 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8678 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8679 // so the error would be seen.
8680 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8681  std::pair<AnsiString, char>TempMapPair;
8682 
8683  ContinuationNameMap.clear();
8684  for(int x = 0; x < Track->TrackVectorSize(); x++)
8685  {
8686  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8687  {
8688  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8689  TempMapPair.second = 'x'; // unused
8690  ContinuationNameMap.insert(TempMapPair);
8691  }
8692  }
8693 //end of addition
8694  CheckLocationNameMultiMap(1); // test
8695  Utilities->CallLogPop(562);
8696 }
8697 
8698 // ---------------------------------------------------------------------------
8699 
8700 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8701 /*
8702  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8703  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8704 */
8705 {
8706  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8707  AnsiString(SpeedTag));
8708  if(!NamedLocationElementAt(2, HLoc, VLoc))
8709  {
8710  Utilities->CallLogPop(948);
8711  return(false);
8712  }
8713  bool FoundFlag;
8714  int Position = -1;
8715  TIMPair IMPair;
8716 
8717  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8718  {
8719  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8720  if(FoundFlag)
8721  {
8722  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8723  {
8724  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8725  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8726  // don't allow duplicates in either list, or processing takes a lot longer
8727  {
8728  FoundElement = MapPos;
8729  Utilities->CallLogPop(563);
8730  return(true);
8731  }
8732  }
8733  }
8734  }
8735  else
8736  {
8737  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8738  if(FoundFlag)
8739  {
8740  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8741  {
8742  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8743  {
8744  FoundElement = IMPair.first;
8745  Utilities->CallLogPop(564);
8746  return(true);
8747  }
8748  }
8749  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8750  {
8751  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8752  {
8753  FoundElement = IMPair.second;
8754  Utilities->CallLogPop(565);
8755  return(true);
8756  }
8757  }
8758  }
8759  }
8760  Utilities->CallLogPop(566);
8761  return(false);
8762 }
8763 
8764 // ---------------------------------------------------------------------------
8765 
8766 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8767 /*
8768  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8769  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8770  with the new name
8771 */
8772 {
8773  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8774  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8775 
8776  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8777  int HLoc = TrackElement->HLoc;
8778  int VLoc = TrackElement->VLoc;
8779  bool FoundFlag;
8780 
8781  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8782  // only have timetable names for adjacent platforms & named locations
8783  {
8784  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8785  if(FoundFlag)
8786  {
8787  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8788  }
8789  }
8790  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8791 
8792  if(ErrorString != "")
8793  {
8794  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8795  }
8796  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8797  CheckLocationNameMultiMap(2); // test
8798  Utilities->CallLogPop(567);
8799 }
8800 
8801 // ---------------------------------------------------------------------------
8802 
8803 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8804 /*
8805  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8806 */
8807 {
8808  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8809  if(LNDone2MultiMap.empty())
8810  {
8811  Utilities->CallLogPop(568);
8812  return(false);
8813  }
8814  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8815 
8816  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8817  {
8818  if(LNDone2MultiMapIterator->second == MapPos)
8819  {
8820  Utilities->CallLogPop(569);
8821  return(true);
8822  }
8823  }
8824  Utilities->CallLogPop(570);
8825  return(false);
8826 }
8827 
8828 // ---------------------------------------------------------------------------
8829 
8830 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8831 /*
8832  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8833 */
8834 {
8835  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8836  if(LNPendingList.empty())
8837  {
8838  Utilities->CallLogPop(571);
8839  return(false);
8840  }
8841  TLNPendingListIterator LNPendingListIterator;
8842 
8843  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8844  {
8845  if(*LNPendingListIterator == MapPos)
8846  {
8847  Utilities->CallLogPop(572);
8848  return(true);
8849  }
8850  }
8851  Utilities->CallLogPop(573);
8852  return(false);
8853 }
8854 
8855 // ---------------------------------------------------------------------------
8856 
8857 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8858 /*
8859  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8860 */
8861 {
8862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8863  THVPair HVPair(HLoc, VLoc);
8864  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8865  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8866 
8867  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8868  {
8869  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8870  {
8871  Utilities->CallLogPop(574);
8872  return(true);
8873  }
8874  }
8875  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8876  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8877  {
8878  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8879  {
8880  Utilities->CallLogPop(575);
8881  return(true);
8882  }
8883  }
8884  Utilities->CallLogPop(576);
8885  return(false);
8886 }
8887 
8888 // ---------------------------------------------------------------------------
8889 
8890 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8891 {
8892  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8893  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8894  {
8895  Utilities->CallLogPop(1953);
8896  return(true);
8897  }
8898  Utilities->CallLogPop(1954);
8899  return(false);
8900 }
8901 
8902 // ---------------------------------------------------------------------------
8903 
8904 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8905 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8906 //program and used when try to save as a .rly file
8907 {
8908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8911  if(LocationNameMultiMap.empty()) //no names so no duplicates
8912  {
8913  Utilities->CallLogPop(2254);
8914  return(false);
8915  }
8916  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8917  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8918  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8919  {
8921  {
8922  if(GiveMessage)
8923  {
8924  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8925  }
8926  Utilities->CallLogPop(2255);
8927  return(true);
8928  }
8929  }
8930  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8931  {
8932  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8933  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8934  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8935  {
8937  {
8938  if(GiveMessage)
8939  {
8940  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8941  }
8942  Utilities->CallLogPop(2256);
8943  return(true);
8944  }
8945  }
8946  }
8947  Utilities->CallLogPop(2257);
8948  return(false); //OK, no duplicates
8949 }
8950 
8951 // ---------------------------------------------------------------------------
8952 
8954 {
8955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8956  THVPair HVPair;
8957  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8958  //for use in the duplicate check
8959  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8960  {
8961  if(LNMMIt->second < 0) //active track element
8962  {
8963  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8964  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8965  }
8966  else //inactive track element
8967  {
8968  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8969  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8970  }
8971  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8972  }
8973  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8974 
8975  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8976  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8977  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8978 
8979  std::list<THVPair> HVLinkedList;
8980 
8981  //set the first value to true and add it to the list
8982  HVPairsLinkedMap.begin()->second = true;
8983  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8984  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8985  //examination
8986  THVPair HVPairUnderExamination;
8987  THVPairsLinkedMap::iterator HVPLMIt;
8988  THVPair HVPairNew;
8989  while(!HVLinkedList.empty())
8990  {
8991  HVPairUnderExamination = HVLinkedList.front();
8992  HVLinkedList.pop_front();
8993  HVPairNew.first = HVPairUnderExamination.first;
8994  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8995  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8996  if(HVPLMIt != HVPairsLinkedMap.end())
8997  {
8998  if(!HVPLMIt->second)
8999  {
9000  HVLinkedList.push_back(HVPLMIt->first);
9001  }
9002  HVPLMIt->second = true;
9003  }
9004  HVPairNew.first = HVPairUnderExamination.first - 1;
9005  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
9006  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9007  if(HVPLMIt != HVPairsLinkedMap.end())
9008  {
9009  if(!HVPLMIt->second)
9010  {
9011  HVLinkedList.push_back(HVPLMIt->first);
9012  }
9013  HVPLMIt->second = true;
9014  }
9015  HVPairNew.first = HVPairUnderExamination.first;
9016  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
9017  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9018  if(HVPLMIt != HVPairsLinkedMap.end())
9019  {
9020  if(!HVPLMIt->second)
9021  {
9022  HVLinkedList.push_back(HVPLMIt->first);
9023  }
9024  HVPLMIt->second = true;
9025  }
9026  HVPairNew.first = HVPairUnderExamination.first + 1;
9027  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
9028  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9029  if(HVPLMIt != HVPairsLinkedMap.end())
9030  {
9031  if(!HVPLMIt->second)
9032  {
9033  HVLinkedList.push_back(HVPLMIt->first);
9034  }
9035  HVPLMIt->second = true;
9036  }
9037  }
9038 
9039  //at the end if any have a false bool then the name is duplicated so return false
9040  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
9041  {
9042  if(!HVPLMIt->second)
9043  {
9044  Utilities->CallLogPop(2258);
9045  return(false);
9046  }
9047  }
9048  Utilities->CallLogPop(2259);
9049  return(true);
9050 }
9051 
9052 // ---------------------------------------------------------------------------
9053 
9054 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
9055 /*
9056  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
9057 */
9058 
9059 {
9060  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
9061  if(LocationName == "")
9062  {
9063  Utilities->CallLogPop(577);
9064  return(false);
9065  }
9066 // new for v0.2b
9067 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
9069  {
9070  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
9071  ActiveTrackElementNameMap.clear();
9072  for(unsigned int x = 0; x < TrackVector.size(); x++)
9073  {
9074  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
9075  == ContinuationNameMap.end())
9076  {
9077  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
9078  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
9079  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
9080  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
9081  }
9082  }
9084  }
9085  Utilities->CallLogPop(578);
9086  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
9087 // end of new section
9088 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
9089 }
9090 
9091 // ---------------------------------------------------------------------------
9092 
9093 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
9094 /*
9095  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
9096  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
9097  new names in the vectors.
9098 */
9099 {
9100  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
9101  bool FoundFlag, ErasedFlag = false;
9102  TLocationNameMultiMapIterator SNIterator;
9103  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9104 
9105  if(SNRange.first != SNRange.second)
9106  {
9107  ErasedFlag = true;
9108  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9109  {
9110  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9111  TVIt->LocationName = "";
9112  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9113  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9114  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9115  {
9116  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9117  if(FoundFlag)
9118  {
9119  TrackElementAt(25, Position).LocationName = "";
9120  TrackElementAt(26, Position).ActiveTrackElementName = "";
9121  }
9122  }
9123  }
9124  }
9125  if(ErasedFlag)
9126  {
9128  }
9129  CheckLocationNameMultiMap(3); // test
9130  Utilities->CallLogPop(579);
9131 }
9132 
9133 // ---------------------------------------------------------------------------
9134 
9135 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9136 /*
9137  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9138  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9139  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9140  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during PlotAndAddTrackElement,
9141  to bring the named location and timetable naming up to date with the deletion or insertion. Note that only one name is sought,
9142  it is entered into LNPendingList and EnterLocationName sets all others.
9143 */
9144 {
9145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9146  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9147  LNPendingList.clear();
9148  AnsiString LocationName;
9149  int MapPos;
9150  bool FoundFlag = 0;
9151 
9152 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9153  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9154  if(FoundFlag)
9155  {
9156  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9157  if(LocationName != "")
9158  {
9159  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9160  EnterLocationName(13, LocationName, true);
9161  Utilities->CallLogPop(2251);
9162  return;
9163  }
9164  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9165  if(LocationName != "")
9166  {
9167  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9168  EnterLocationName(14, LocationName, true);
9169  Utilities->CallLogPop(2252);
9170  return;
9171  }
9172  }
9173 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9174 
9175  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9176  if(FoundFlag)
9177  {
9178  LocationName = TrackElementAt(1004, Position).LocationName;
9179  if(LocationName != "")
9180  {
9181  int ModifiedPosition = -1 - Position;
9182  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9183  EnterLocationName(15, LocationName, true);
9184  Utilities->CallLogPop(2253);
9185  return;
9186  }
9187  }
9188  if(SpeedTag == 76) // top plat
9189  {
9190  for(int x = 0; x < 25; x++)
9191  {
9192  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9193  {
9194  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9195  EnterLocationName(3, LocationName, true);
9196  break;
9197  }
9198  }
9199  }
9200  else if(SpeedTag == 77) // bot plat
9201  {
9202  for(int x = 0; x < 25; x++)
9203  {
9204  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9205  {
9206  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9207  EnterLocationName(4, LocationName, true);
9208  break;
9209  }
9210  }
9211  }
9212  else if(SpeedTag == 78) // l plat
9213  {
9214  for(int x = 0; x < 25; x++)
9215  {
9216  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9217  {
9218  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9219  EnterLocationName(5, LocationName, true);
9220  break;
9221  }
9222  }
9223  }
9224  else if(SpeedTag == 79) // r plat
9225  {
9226  for(int x = 0; x < 25; x++)
9227  {
9228  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9229  {
9230  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9231  EnterLocationName(6, LocationName, true);
9232  break;
9233  }
9234  }
9235  }
9236  else if(SpeedTag == 96) // conc
9237  {
9238  for(int x = 0; x < 28; x++)
9239  {
9240  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9241  {
9242  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9243  EnterLocationName(7, LocationName, true);
9244  break;
9245  }
9246  }
9247  }
9248  else if(SpeedTag == 129) // vert footbridge
9249  {
9250  for(int x = 0; x < 8; x++)
9251  {
9252  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9253  {
9254  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9255  EnterLocationName(8, LocationName, true);
9256  break;
9257  }
9258  }
9259  }
9260  else if(SpeedTag == 130) // hor footbridge
9261  {
9262  for(int x = 0; x < 8; x++)
9263  {
9264  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9265  {
9266  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9267  EnterLocationName(9, LocationName, true);
9268  break;
9269  }
9270  }
9271  }
9272  else if(SpeedTag == 145) // vert u'pass
9273  {
9274  for(int x = 0; x < 8; x++)
9275  {
9276  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9277  {
9278  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9279  EnterLocationName(11, LocationName, true);
9280  break;
9281  }
9282  }
9283  }
9284  else if(SpeedTag == 146) // hor u'pass
9285  {
9286  for(int x = 0; x < 8; x++)
9287  {
9288  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9289  {
9290  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9291  EnterLocationName(12, LocationName, true);
9292  break;
9293  }
9294  }
9295  }
9296  else if(SpeedTag == 131) // named location
9297  {
9298  for(int x = 0; x < 4; x++)
9299  {
9300  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9301  {
9302  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9303  EnterLocationName(10, LocationName, true);
9304  Utilities->CallLogPop(2657);
9305  return;
9306  }
9307  }
9308  int TVPos = GetVectorPositionFromTrackMap(68, HLoc, VLoc, FoundFlag); //deal with gaps, added at v2.18.0
9309  {
9310  if(FoundFlag && TrackElementAt(1589, TVPos).TrackType == GapJump)
9311  {
9312  int GJTVPos = TrackElementAt(1590, TVPos).Conn[0];
9313  if(GJTVPos > -1)
9314  {
9315  int HLoc2 = TrackElementAt(1591, GJTVPos).HLoc;
9316  int VLoc2 = TrackElementAt(1592, GJTVPos).VLoc;
9317  LocationName = TrackElementAt(1593, GJTVPos).ActiveTrackElementName;
9318  bool FoundFlag2 = false;
9319  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(34, HLoc2, VLoc2, FoundFlag2);
9320  if(FoundFlag2)
9321  {
9322  if(Track->InactiveTrackElementAt(1411, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
9323  {
9324  LNPendingList.insert(LNPendingList.end(), IMPair.first);
9325  EnterLocationName(16, LocationName, true);
9326  }
9327  }
9328  }
9329  }
9330  }
9331  }
9332 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9333  Utilities->CallLogPop(580);
9334 }
9335 
9336 // ---------------------------------------------------------------------------
9337 
9338 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9339 /*
9340  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9341  true if a LocationName is found, and also returns the name and the adjusted vector position.
9342 */
9343 {
9344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9345  AnsiString(SpeedTag));
9346  bool FoundFlag;
9347  TIMPair IMPair;
9348  TTrackVectorIterator TempElement;
9349  int Position;
9350 
9351  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9352  if(FoundFlag)
9353  {
9354  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9355  {
9356  TempElement = InactiveTrackVector.begin() + IMPair.first;
9357  if(TempElement->LocationName != "")
9358  {
9359  LocationName = TempElement->LocationName;
9360  FoundElement = IMPair.first;
9361  Utilities->CallLogPop(581);
9362  return(true);
9363  }
9364  }
9365  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9366  {
9367  TempElement = InactiveTrackVector.begin() + IMPair.second;
9368  if(TempElement->LocationName != "")
9369  {
9370  LocationName = TempElement->LocationName;
9371  FoundElement = IMPair.second;
9372  Utilities->CallLogPop(582);
9373  return(true);
9374  }
9375  }
9376  }
9377  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9378  if(FoundFlag)
9379  {
9380  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9381  {
9382  TempElement = TrackVector.begin() + Position;
9383  if(TempElement->LocationName != "")
9384  {
9385  LocationName = TempElement->LocationName;
9386  FoundElement = -1 - Position;
9387  Utilities->CallLogPop(583);
9388  return(true);
9389  }
9390  }
9391  }
9392  Utilities->CallLogPop(584);
9393  return(false);
9394 }
9395 
9396 // ---------------------------------------------------------------------------
9397 
9398 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9399 {
9400 // check quantity in map & vectors match
9401  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9402  unsigned int Count = 0;
9403 
9404  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9405  {
9406  Utilities->CallLogPop(2059);
9407  return;
9408  }
9409  AnsiString SName, TName, ErrorString;
9410 
9411  for(unsigned int x = 0; x < TrackVector.size(); x++)
9412  {
9413  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9414  {
9415  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9416  {
9417  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9418  AnsiString(Caller));
9419  }
9420  Count++;
9421  }
9422  }
9423  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9424  {
9425  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9426  {
9427  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9428  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9429  {
9430  throw Exception
9431  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9432  AnsiString(Caller));
9433  }
9434  Count++;
9435  }
9436  }
9437  if(LocationNameMultiMap.size() != Count)
9438  {
9439  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9440  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9441  }
9442 // check all entries in both vectors match entries in name multimap
9444 
9445  for(unsigned int x = 0; x < TrackVector.size(); x++)
9446  {
9447  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9448  {
9449  SName = TrackElementAt(1365, x).LocationName;
9450  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9451  if(ErrorString != "")
9452  {
9453  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9454  }
9455  if(SNIt->second != -1 - (int)x)
9456  {
9457  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9458  AnsiString(Caller));
9459  }
9460  }
9461  // check corresponding platform for all Timetable entries that aren't empty
9462  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9463  TIMPair IMPair;
9464  bool FoundFlag = false;
9465  if(TName != "")
9466  {
9467  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9468  if(FoundFlag)
9469  {
9470  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9472  {
9473  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9474  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9475  }
9476  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9477  {
9478  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9479  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9480  AnsiString(Caller));
9481  }
9482  }
9483  else
9484  {
9485  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9486  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9487  }
9488  }
9489  }
9490  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9491  {
9492  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9493  {
9494  SName = InactiveTrackElementAt(148, x).LocationName;
9495  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9496  if(ErrorString != "")
9497  {
9498  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9499  }
9500  if(SNIt->second != (int)x)
9501  {
9502  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9503  AnsiString(Caller));
9504  }
9505  }
9506  }
9507  Utilities->CallLogPop(585);
9508 }
9509 
9510 // ---------------------------------------------------------------------------
9511 
9513  AnsiString &ErrorString)
9514 {
9515 /*
9516  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9517  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9518  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9519 */
9520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9521  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9522  ErrorString = "";
9523  bool FoundFlag = false;
9524  TLocationNameMultiMapIterator SNIterator;
9525  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9526 
9527  if(SNRange.first == SNRange.second)
9528  {
9529  ErrorString = "Error, Name " + LocationName + " not found in map";
9530  Utilities->CallLogPop(586);
9531  return(SNRange.first);
9532  }
9533  else
9534  {
9535  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9536  {
9537  if(SNIterator->second < 0)
9538  {
9539  int TVPos = -1 - SNIterator->second;
9540  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9541  if(TVIt == TrackElement)
9542  {
9543  FoundFlag = true;
9544  Utilities->CallLogPop(587);
9545  return(SNIterator);
9546  }
9547  }
9548  else
9549  {
9550  int ITVPos = SNIterator->second;
9551  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9552  if(ITVIt == TrackElement)
9553  {
9554  FoundFlag = true;
9555  Utilities->CallLogPop(588);
9556  return(SNIterator);
9557  }
9558  }
9559  }
9560  }
9561  if(!FoundFlag)
9562  {
9563  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9564  }
9565  Utilities->CallLogPop(589);
9566  return(SNIterator);
9567 }
9568 
9569 // ---------------------------------------------------------------------------
9570 
9571 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9572 {
9573 /*
9574  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9575  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9576 */
9577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9578  TLocationNameMultiMapEntry LocationNameEntry;
9579 
9580  LocationNameEntry.first = NewName;
9581  LocationNameEntry.second = SNIterator->second;
9582  LocationNameMultiMap.erase(SNIterator);
9583  LocationNameMultiMap.insert(LocationNameEntry);
9584  Utilities->CallLogPop(590);
9585 }
9586 
9587 // ---------------------------------------------------------------------------
9588 
9590 {
9591 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9592  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9593  if(Position < 0) // footcrossing
9594  {
9595  int TruePos = -1 - Position;
9596  // new check at v0.2b
9597  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9598  {
9599  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9600  }
9601  Utilities->CallLogPop(591);
9602  return (TrackVector.begin() + TruePos);
9603  }
9604  else
9605  {
9606  // new check at v0.2b
9607  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9608  {
9609  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9610  }
9611  Utilities->CallLogPop(592);
9612  return (InactiveTrackVector.begin() + Position);
9613  }
9614 }
9615 
9616 // ---------------------------------------------------------------------------
9617 
9618 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9619 {
9620 /*
9621  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9622  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9623  LocationNameMultiMap.
9624 */
9625  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9626  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9627  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9628 
9629  if(!InactiveTrack2MultiMap.empty())
9630  {
9631  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9632  InactiveTrack2MultiMapIterator++)
9633  {
9634  if(InactiveTrack2MultiMapIterator->second > VecPos)
9635  {
9636  InactiveTrack2MultiMapIterator->second--;
9637  }
9638  // can't be == VecPos as that position erased
9639  }
9640  }
9641  if(!LocationNameMultiMap.empty())
9642  {
9643  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9644  LocationNameMultiMapIterator++)
9645  {
9646  if(LocationNameMultiMapIterator->second < 0)
9647  {
9648  continue; // deal with TrackVectors separately
9649  }
9650  if(LocationNameMultiMapIterator->second > (int)VecPos)
9651  {
9652  LocationNameMultiMapIterator->second--;
9653  }
9654  }
9655  }
9656  Utilities->CallLogPop(593);
9657 }
9658 
9659 // ---------------------------------------------------------------------------
9660 
9661 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9662 {
9663 /*
9664  After an element has been erased from the track vector, all the later elements are moved down one. This function
9665  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9666  LocationNameMultiMap.
9667 */
9668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9669  TTrackMapIterator TrackMapIterator;
9670  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9671 
9672  if(!TrackMap.empty())
9673  {
9674  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9675  {
9676  if(TrackMapIterator->second > VecPos)
9677  {
9678  TrackMapIterator->second--;
9679  }
9680  // can't be == VecPos as that position erased
9681  }
9682  }
9683  if(!LocationNameMultiMap.empty())
9684  {
9685  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9686  LocationNameMultiMapIterator++)
9687  {
9688  if(LocationNameMultiMapIterator->second >= 0)
9689  {
9690  continue; // deal with InactiveTrackVectors separately
9691  }
9692  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9693  // Val -1 -2 -3 -4 -5 -6 -7 -8
9694  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9695  {
9696  LocationNameMultiMapIterator->second++;
9697  }
9698  }
9699  }
9700  for(unsigned int x = 0; x < TrackVector.size(); x++)
9701  {
9702  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9703  if(TkEl.TrackType == GapJump)
9704  {
9705  // position 0 is the gap
9706  if(TkEl.Conn[0] == int(VecPos))
9707  {
9708  TkEl.Conn[0] = -1; // connected to a deleted gap
9709  continue;
9710  }
9711  if(TkEl.Conn[0] > int(VecPos))
9712  {
9713  TkEl.Conn[0]--;
9714  }
9715  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9716  {
9717  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9718  {
9719  TkEl.Conn[0] = -1;
9720  }
9721  }
9722  }
9723  }
9724  Utilities->CallLogPop(1433);
9725 }
9726 
9727 // ---------------------------------------------------------------------------
9728 
9730 /*
9731  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9732  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9733  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9734  InactiveTrackvector values are stored as they are, 0 to n, whereas ActiveTrackvector values stored as -1 - TVPos, i.e.
9735  running from -1 to -1 - n
9736 */
9737 {
9738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9739  LocationNameMultiMap.clear();
9740  TLocationNameMultiMapEntry LocationNameEntry;
9741  TTrackElement TrackElement;
9742 
9743  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9744  {
9745  TrackElement = TrackElementAt(1376, TVPos);
9746  if(TrackElement.FixedNamedLocationElement)
9747  {
9748  LocationNameEntry.first = TrackElement.LocationName;
9749  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9750  LocationNameMultiMap.insert(LocationNameEntry);
9751  }
9752  }
9753 
9754  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9755  {
9756  TrackElement = InactiveTrackElementAt(149, ITVPos);
9757  if(TrackElement.FixedNamedLocationElement)
9758  {
9759  LocationNameEntry.first = TrackElement.LocationName;
9760  LocationNameEntry.second = ITVPos;
9761  LocationNameMultiMap.insert(LocationNameEntry);
9762  }
9763  }
9764  Utilities->CallLogPop(594);
9765 }
9766 
9767 // ---------------------------------------------------------------------------
9768 
9770 // Return true if there is a named location present in the railway
9771 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9772 {
9773  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9774  TTrackVectorIterator ITVI;
9775 
9776  if(InactiveTrackVector.empty())
9777  {
9778  Utilities->CallLogPop(1343);
9779  return(false);
9780  }
9781  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9782  {
9783  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9784  {
9785  Utilities->CallLogPop(1404);
9786  return(true);
9787  }
9788  }
9789  Utilities->CallLogPop(1344);
9790  return(false);
9791 }
9792 
9793 // ---------------------------------------------------------------------------
9794 
9796 /*
9797  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9798 */
9799 {
9800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9801 // ResetDistanceElements(6);
9802  for(unsigned int x = 0; x < TrackVector.size(); x++)
9803  {
9804  TTrackElement &TE = TrackElementAt(718, x);
9807  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9808  {
9811  }
9812  }
9813 /* old function
9814  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9815  {
9816  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9817  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9818  }
9819  else
9820  {
9821  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9822  }
9823  }
9824 */
9825  Utilities->CallLogPop(617);
9826 }
9827 
9828 // ---------------------------------------------------------------------------
9829 
9830 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9831 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9832 {
9833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9834  for(unsigned int x = 0; x < TrackVector.size(); x++)
9835  {
9836  TTrackElement TempElement = TrackElementAt(1377, x);
9837  if(TempElement.Length01 > -1)
9838  {
9839  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9840  }
9841  if(TempElement.Length23 > -1)
9842  {
9843  MarkOneLength(2, TempElement, false, Disp);
9844  }
9845  }
9846  Disp->Update();
9847  Utilities->CallLogPop(618);
9848 }
9849 
9850 // ---------------------------------------------------------------------------
9851 
9852 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9853 /*
9854  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
9855  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9856  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9857  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9858  track as indicated by FirstTrack (true for track01 & false for track23).
9859 */
9860 {
9861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9862  AnsiString((short)FirstTrack));
9863  bool LengthDifferent = false, SpeedDifferent = false;
9864 
9865  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9866  {
9867  Utilities->CallLogPop(619);
9868  return;
9869  }
9870  int EXArray[16][2] =
9871  {{4, 6}, {2, 8}, // horizontal & vertical
9872  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9873  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9874  {1, 9}, {3, 7}}; // forward & reverse diagonals
9875 
9876  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9877  Graphics::TBitmap *Bitmap;
9878 
9879  if(FirstTrack)
9880  {
9881  InLink = TrackElement.Link[0];
9882  OutLink = TrackElement.Link[1];
9883  }
9884  else
9885  {
9886  InLink = TrackElement.Link[2];
9887  OutLink = TrackElement.Link[3];
9888  }
9889  for(int x = 0; x < 16; x++)
9890  {
9891  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9892  {
9893  Index = x;
9894  }
9895  }
9896  if(Index == -1)
9897  {
9898  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9899  }
9900 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9901  the graphic for each of which is different because of the shape of the overbridge. The basic
9902  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9903  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9904  int BrEXArray[24][2] = {
9905  {4,6},{2,8},{1,9},{3,7},
9906  {1,9},{3,7},{1,9},{3,7},
9907  {2,8},{4,6},{2,8},{4,6}
9908 */
9909  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9910  {
9911  if(Index == 1)
9912  {
9913  if(TrackElement.SpeedTag == 49)
9914  {
9915  BrNum = 1 + 16;
9916  }
9917  else if(TrackElement.SpeedTag == 54)
9918  {
9919  BrNum = 8 + 16;
9920  }
9921  else if(TrackElement.SpeedTag == 55)
9922  {
9923  BrNum = 10 + 16;
9924  }
9925  }
9926  else if(Index == 0)
9927  {
9928  if(TrackElement.SpeedTag == 48)
9929  {
9930  BrNum = 0 + 16;
9931  }
9932  else if(TrackElement.SpeedTag == 58)
9933  {
9934  BrNum = 11 + 16;
9935  }
9936  else if(TrackElement.SpeedTag == 59)
9937  {
9938  BrNum = 9 + 16;
9939  }
9940  }
9941  else if(Index == 14)
9942  {
9943  if(TrackElement.SpeedTag == 50)
9944  {
9945  BrNum = 2 + 16;
9946  }
9947  else if(TrackElement.SpeedTag == 52)
9948  {
9949  BrNum = 4 + 16;
9950  }
9951  else if(TrackElement.SpeedTag == 57)
9952  {
9953  BrNum = 6 + 16;
9954  }
9955  }
9956  else if(Index == 15)
9957  {
9958  if(TrackElement.SpeedTag == 51)
9959  {
9960  BrNum = 3 + 16;
9961  }
9962  else if(TrackElement.SpeedTag == 53)
9963  {
9964  BrNum = 7 + 16;
9965  }
9966  else if(TrackElement.SpeedTag == 56)
9967  {
9968  BrNum = 5 + 16;
9969  }
9970  }
9971  }
9972  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9973  {
9974  GrNum = BrNum;
9975  }
9976  else
9977  {
9978  GrNum = Index;
9979  }
9980  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9981  {
9982  if(GrNum > 15) // underbridge
9983  {
9984  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9985  }
9986  else
9987  {
9988  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9989  }
9990  if(TrackElement.SpeedTag == 64)
9991  {
9992  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9993  }
9994  if(TrackElement.SpeedTag == 65)
9995  {
9997  }
9998  if(TrackElement.SpeedTag == 66)
9999  {
10001  }
10002  if(TrackElement.SpeedTag == 67)
10003  {
10005  }
10006  if(TrackElement.SpeedTag == 80)
10007  {
10008  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
10009  }
10010  if(TrackElement.SpeedTag == 81)
10011  {
10013  }
10014  if(TrackElement.SpeedTag == 82)
10015  {
10017  }
10018  if(TrackElement.SpeedTag == 83)
10019  {
10021  }
10022  if(TrackElement.SpeedTag == 84)
10023  {
10025  }
10026  if(TrackElement.SpeedTag == 85)
10027  {
10029  }
10030  if(TrackElement.SpeedTag == 86)
10031  {
10033  }
10034  if(TrackElement.SpeedTag == 87)
10035  {
10037  }
10038  if(TrackElement.SpeedTag == 129)
10039  {
10040  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
10041  }
10042  if(TrackElement.SpeedTag == 130)
10043  {
10045  }
10046  }
10047 
10048  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
10049  {
10050  if(GrNum > 15) // underbridge
10051  {
10052  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
10053  }
10054  else
10055  {
10056  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
10057  }
10058  if(TrackElement.SpeedTag == 64)
10059  {
10060  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10061  }
10062  if(TrackElement.SpeedTag == 65)
10063  {
10064  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
10065  }
10066  if(TrackElement.SpeedTag == 66)
10067  {
10068  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
10069  }
10070  if(TrackElement.SpeedTag == 67)
10071  {
10072  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
10073  }
10074  if(TrackElement.SpeedTag == 80)
10075  {
10076  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10077  }
10078  if(TrackElement.SpeedTag == 81)
10079  {
10080  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
10081  }
10082  if(TrackElement.SpeedTag == 82)
10083  {
10084  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
10085  }
10086  if(TrackElement.SpeedTag == 83)
10087  {
10088  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
10089  }
10090  if(TrackElement.SpeedTag == 84)
10091  {
10092  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
10093  }
10094  if(TrackElement.SpeedTag == 85)
10095  {
10096  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
10097  }
10098  if(TrackElement.SpeedTag == 86)
10099  {
10100  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
10101  }
10102  if(TrackElement.SpeedTag == 87)
10103  {
10104  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
10105  }
10106  if(TrackElement.SpeedTag == 129)
10107  {
10108  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
10109  }
10110  if(TrackElement.SpeedTag == 130)
10111  {
10112  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
10113  }
10114  }
10115 
10116  else // SpeedDifferent only: red - use non sig graphics
10117  {
10118  if(GrNum > 15) // underbridge
10119  {
10120  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
10121  }
10122  else
10123  {
10124  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
10125  }
10126  if(TrackElement.SpeedTag == 64)
10127  {
10128  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10129  }
10130  if(TrackElement.SpeedTag == 65)
10131  {
10133  }
10134  if(TrackElement.SpeedTag == 66)
10135  {
10137  }
10138  if(TrackElement.SpeedTag == 67)
10139  {
10141  }
10142  if(TrackElement.SpeedTag == 80)
10143  {
10144  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10145  }
10146  if(TrackElement.SpeedTag == 81)
10147  {
10149  }
10150  if(TrackElement.SpeedTag == 82)
10151  {
10153  }
10154  if(TrackElement.SpeedTag == 83)
10155  {
10157  }
10158  if(TrackElement.SpeedTag == 84)
10159  {
10161  }
10162  if(TrackElement.SpeedTag == 85)
10163  {
10165  }
10166  if(TrackElement.SpeedTag == 86)
10167  {
10169  }
10170  if(TrackElement.SpeedTag == 87)
10171  {
10173  }
10174  if(TrackElement.SpeedTag == 129)
10175  {
10176  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10177  }
10178  if(TrackElement.SpeedTag == 130)
10179  {
10181  }
10182  }
10183  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10184  Utilities->CallLogPop(620);
10185 }
10186 
10187 // ---------------------------------------------------------------------------
10188 
10189 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10190 /* FirstTrack = LinkPos's 0 & 1
10191  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10192 */
10193 {
10194  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
10195  AnsiString((short)FirstTrack));
10196  LengthDifferent = false;
10197  SpeedDifferent = false;
10198  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10199  {
10200  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10201  {
10202  LengthDifferent = true;
10203  }
10204  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10205  {
10206  SpeedDifferent = true;
10207  }
10208  if(LengthDifferent || SpeedDifferent)
10209  {
10210  Utilities->CallLogPop(625);
10211  return(false);
10212  }
10213  Utilities->CallLogPop(626);
10214  return(true);
10215  }
10216 
10217  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10218  {
10219  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10220  {
10221  LengthDifferent = true;
10222  }
10223  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10224  {
10225  SpeedDifferent = true;
10226  }
10227  if(LengthDifferent || SpeedDifferent)
10228  {
10229  Utilities->CallLogPop(627);
10230  return(false);
10231  }
10232  Utilities->CallLogPop(628);
10233  return(true);
10234  }
10235 
10236  else // any other 1 track element, including platforms being present
10237  {
10238  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10239  {
10240  LengthDifferent = true;
10241  }
10242  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10243  {
10244  SpeedDifferent = true;
10245  }
10246  if(LengthDifferent || SpeedDifferent)
10247  {
10248  Utilities->CallLogPop(629);
10249  return(false);
10250  }
10251  Utilities->CallLogPop(630);
10252  return(true);
10253  }
10254 }
10255 
10256 // ---------------------------------------------------------------------------
10257 
10258 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10259 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10260 {
10261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10262  AnsiString(VLoc));
10263  bool FoundFlag;
10264  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10265 
10266  if(!FoundFlag)
10267  {
10268  Utilities->CallLogPop(633);
10269  return(false);
10270  }
10271  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10272  {
10273  Utilities->CallLogPop(634);
10274  return(true); // only need to check first since if second is a platform the the first must be too
10275  }
10276  else
10277  {
10278  Utilities->CallLogPop(635);
10279  return(false);
10280  }
10281 }
10282 
10283 // ---------------------------------------------------------------------------
10284 
10285 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10286 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10287 {
10288  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10289  AnsiString(VLoc));
10290  bool FoundFlag;
10291  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10292 
10293  if(!FoundFlag)
10294  {
10295  Utilities->CallLogPop(636);
10296  return(false);
10297  }
10299  {
10300  Utilities->CallLogPop(637);
10301  return(true); // only need to check first since only one used for NamedNonStationLocations
10302  }
10303  else
10304  {
10305  Utilities->CallLogPop(638);
10306  return(false);
10307  }
10308 }
10309 
10310 // ---------------------------------------------------------------------------
10311 
10312 void TTrack::SetStationEntryStopLinkPosses(int Caller) //only for platforms
10313 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10314  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10315  the front of train stop points for each direction.
10316  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10317  end (unless buffers at one or both ends in which case stop points are the end elements).
10318  Note that for a single element the stop point is the element itself (formula doesn't apply).
10319  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10320  repeating the procedure for every element. At the end all unused values are returned to -1.
10321  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10322 */
10323 {
10324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10325  TTrackElement TempElement, StartElement;
10326  AnsiString TempName;
10327  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10328  bool ForwardSet, ReverseSet;
10329 
10330  for(unsigned int x = 0; x < TrackVector.size(); x++)
10331  {
10332  TrackElementAt(1378, x).StationEntryStopLinkPos1 = -1; //this only sets 0 & 1 as all single track elements for platforms
10334  }
10335  for(unsigned int x = 0; x < TrackVector.size(); x++)
10336  {
10337  TempElement = TrackElementAt(1380, x);
10338  if(!IsNamedNonStationLocationPresent(2, TempElement.HLoc, TempElement.VLoc)) //deal with non-station names later
10339  {
10340  ForwardSet = false;
10341  ReverseSet = false;
10342  VecPos = x;
10343  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1) && (TempElement.StationEntryStopLinkPos2 == -1))
10344  // 2nd condition incl so don't re-examine elements with stop links set to 5
10345  {
10346  TempName = TempElement.ActiveTrackElementName;
10347  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10348  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10349  // an element linked at both ends where both links are also named elements
10350  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10351  {
10352  continue; // looking for an end element so skip this one
10353  }
10354  else // reached one end
10355  {
10356  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10357  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10358  // single named element linked at both ends, can't be continuation as platforms not allowed there
10359  {
10360  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10361  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10362  continue;
10363  }
10364  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10365  // single named buffer element (LinkPos 1 is the non-buffer end)
10366  {
10367  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10368  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10369  continue;
10370  }
10371  else
10372  // Note: only interested in connection positions 0 & 1 since all platform elements are single track except points,
10373  // and platforms always on straight (conns 0 & 1) section of points
10374  {
10375  for(int y = 0; y < 2; y++)
10376  {
10377  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10378  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10379  /* TTrackElement Temp1 = TempElement;
10380  ***********New section, compiles but not checked - does bit below need to be else if?
10381  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10382  {
10383  //search along Dir direction until find other end, skip if Dir facing buffer end
10384  int NewDir = Dir;
10385  int NewVecPos;
10386  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10387  {
10388  NewVecPos = Temp1.Conn[NewDir];
10389  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10390  Temp1 = TrackElementAt(601, NewVecPos);
10391  }
10392  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10393  {
10394  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10395  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10396  }
10397  }
10398  ***************
10399  */
10400  // end may be linked at both ends but only one link named, or buffer with linked element named
10401  // if a buffer then the named linkpos has to be 1
10402  // already dealt with all types of single element so at least 2 linked named elements
10403  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10404  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10405  { //element linked at both ends with entry end not same name, or buffers with exit link == 1 (exit link always 1 but need to ensure Dir set correctly)
10406  StartElement = TempElement;
10407  StartVecPos = VecPos; //this stays fixed at start of platform group
10408  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10409  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10410  EntryPos = 1 - Dir;
10411  StartEntryPos = 1 - Dir;
10412  Count = 1;
10413  // work along named elements until find the other end
10414  while((TempElement.Conn[1 - EntryPos] > -1) && (TempElement.Conn[1 - EntryPos] < (int)TrackVector.size()) && (TrackElementAt(53, TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10415  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10416  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10417  // all stop link pos's are set to 5
10418  {
10419  VecPos = TempElement.Conn[1 - EntryPos];
10420  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10421  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10422  EntryPos = TempEntryPos;
10423  Count++;
10424  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10425  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10426  }
10427  // here when reached other end, maybe buffers, or last named linked element
10428  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10429  // terminal station, set end elements as stop elements
10430  {
10431  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10432  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10433  continue;
10434  }
10435  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10436  // terminal station, set end elements as stop elements
10437  {
10438  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10439  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10440  continue;
10441  }
10442  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10443  ForwardNumber = ((Count + 1) / 2) + 1;
10444  ReverseNumber = (Count - ForwardNumber) + 1;
10445  Count = 1; // starting value
10446  EntryPos = 1 - Dir;
10447  TempElement = StartElement;
10448  VecPos = StartVecPos;
10449  if(Count == ForwardNumber)
10450  {
10451  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10452  ForwardSet = true;
10453  }
10454  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10455  {
10456  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10457  ReverseSet = true;
10458  }
10459  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10460  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10461  {
10462  VecPos = TempElement.Conn[1 - EntryPos];
10463  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10464  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10465  EntryPos = TempEntryPos;
10466  Count++;
10467  if(Count == ForwardNumber)
10468  {
10469  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10470  ForwardSet = true;
10471  }
10472  if(Count == ReverseNumber)
10473  {
10474  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10475  ReverseSet = true;
10476  }
10477  }
10478  }
10479  }
10480  }
10481  }
10482  }
10483  }
10484  }
10485  for(unsigned int x = 0; x < TrackVector.size(); x++)
10486  {
10487  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10488  {
10490  }
10491  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10492  {
10494  }
10495  }
10496  Utilities->CallLogPop(639);
10497 }
10498 
10499 // ---------------------------------------------------------------------------
10500 
10501 void TTrack::SetNonStationStopLinkEntryPosses(int Caller) //added at v2.18.0
10502 
10503 {
10504 /*at v2.18.0 allow for 2 tracks on a non-station element. Have StationEntryStopLinkPos1 & 2 contain both track entry positions, 0 & 1 in
10505 least sig 2 bits and 2 & 3 in next least sig bits. In use have SESLPos1a == 0 or 1 and SESLPos1b == 2 or 3, and same for Pos2. 'b' values all
10506 set to 0 for platforms, and set appropriately for 2-track non-station locs. SESLPos values are TTrackElement variables only used in program, not
10507 saved in sessions or railways (same as StationEntryStopLinkPos1 & 2).
10508 
10509 Examine each non-station area with same name and, similar to above, look for cases where a track doesn't link to an element with the same name, or
10510 doesn't link at all, this is an end element, check both tracks separately for 4-track elements.
10511 */
10512  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetNonStationStopLinkEntryPosses");
10513  TTrackElement TempElement;
10514  AnsiString TempName;
10515  std::list<unsigned int> NameList; //end elements
10516  std::list<AnsiString> ContinuationNameList; // list of continuation names so can exclude them
10517  for(unsigned int x = 0; x < TrackVector.size(); x++)
10518  {
10519  TrackElementAt(1594, x).StationEntryStopLinkPos3 = -1; // don't clear stopping points 0 & 1 as already set for platforms
10521  if((TrackElementAt(1596, x).TrackType == Continuation) && (TrackElementAt(1641, x).ActiveTrackElementName != ""))
10522  {
10523  ContinuationNameList.push_back(TrackElementAt(1597, x).ActiveTrackElementName);
10524  }
10525  }
10526  ContinuationNameList.sort();
10527  ContinuationNameList.unique();
10528 
10529  for(unsigned int x = 0; x < TrackVector.size(); x++)
10530  {
10531  TempElement = TrackElementAt(1598, x);
10532  if(IsNamedNonStationLocationPresent(3, TempElement.HLoc, TempElement.VLoc))
10533  {
10534  bool NameIsAContinuation = false;
10535  if(std::find(ContinuationNameList.begin(), ContinuationNameList.end(), TempElement.ActiveTrackElementName) != ContinuationNameList.end())
10536  {
10537  NameIsAContinuation = true;
10538  }
10539  if((TempElement.ActiveTrackElementName != "") && !NameIsAContinuation && (TempElement.StationEntryStopLinkPos1 == -1) &&
10540  (TempElement.StationEntryStopLinkPos2 == -1) && (TempElement.StationEntryStopLinkPos3 == -1) && (TempElement.StationEntryStopLinkPos4 == -1))
10541  // Non-station named elements can't be placed on platforms so no conflict with existing stop positions
10542  {
10543  TempName = TempElement.ActiveTrackElementName;
10544  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(1599, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10545  (TrackElementAt(1600, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10546  // an element linked at both ends of single or main track where both links are also named elements with same name
10547  {
10548  if(TempElement.TrackType == Points) //for points links 0 and 2 are the same
10549  {
10550  if(((TempElement.Conn[2] > -1)) && (TempElement.Conn[3] > -1) &&
10551  ((TrackElementAt(1601, TempElement.Conn[2]).ActiveTrackElementName == TempName)) &&
10552  (TrackElementAt(1602, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10553  {
10554  continue; //not an end element so skip it
10555  }
10556  else //reached an end on the diverging leg
10557  {
10558  NameList.push_back(x);
10559  }
10560  }
10561  else if(TempElement.TrackType == Crossover)
10562  {
10563  if((TempElement.Conn[2] > -1) && (TempElement.Conn[3] > -1) &&
10564  (TrackElementAt(1603, TempElement.Conn[2]).ActiveTrackElementName == TempName) &&
10565  (TrackElementAt(1604, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10566  {
10567  continue; //not an end element so skip it
10568  }
10569  else
10570  {
10571  NameList.push_back(x);
10572  }
10573  }
10574  else
10575  {
10576  continue; //not points ot crossover & not an end element so skip
10577  }
10578  }
10579  else // reached one end of single or main track
10580  {
10581  NameList.push_back(x);
10582  }
10583 //NameList now contains all non-station end elements
10584  while(!NameList.empty())
10585  {
10586  unsigned int a = NameList.front();
10587  NameList.pop_front();
10588  TTrackElement &TempElement = TrackElementAt(1605, a);
10589  AnsiString TempName = TempElement.ActiveTrackElementName;
10590  if(TempElement.TrackType == Buffers) //buffer end is 0 so entry must be 1, gaps covered below as any other element
10591  {
10592  TempElement.StationEntryStopLinkPos1 = 1;
10593  }
10594  else
10595  {
10596  if((TempElement.Conn[0] == -1) || (TrackElementAt(1606, TempElement.Conn[0]).ActiveTrackElementName != TempName))
10597  {
10598  TempElement.StationEntryStopLinkPos1 = 1;
10599  }
10600  if((TempElement.Conn[1] == -1) || (TrackElementAt(1607, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10601  {
10602  TempElement.StationEntryStopLinkPos2 = 0;
10603  }
10604  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover))
10605  {
10606  if((TempElement.Conn[2] == -1) || (TrackElementAt(1608, TempElement.Conn[2]).ActiveTrackElementName != TempName))
10607  {
10608  TempElement.StationEntryStopLinkPos3 = 3;
10609  }
10610  if((TempElement.Conn[3] == -1) || (TrackElementAt(1609, TempElement.Conn[3]).ActiveTrackElementName != TempName))
10611  {
10612  TempElement.StationEntryStopLinkPos4 = 2;
10613  }
10614  }
10615  }
10616  }
10617  }
10618  }
10619  }
10620  Utilities->CallLogPop(2640);
10621 }
10622 
10623 // ---------------------------------------------------------------------------
10624 
10625 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10626 {
10627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10628  TTrackElement Next;
10629 
10631  while(ReturnNextInactiveTrackElement(1, Next))
10632  {
10633  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10634  {
10635  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10636  // need striped graphics
10637  {
10638  if(Next.SpeedTag == 76)
10639  {
10640  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10641  }
10642  else if(Next.SpeedTag == 77)
10643  {
10644  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10645  }
10646  else if(Next.SpeedTag == 78)
10647  {
10648  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10649  }
10650  else if(Next.SpeedTag == 79)
10651  {
10652  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10653  }
10654  else if(Next.SpeedTag == 96)
10655  {
10656  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10657  }
10658  else if(Next.SpeedTag == 131)
10659  {
10660  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10661  }
10662  }
10663  else
10664  {
10665  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10666  }
10667  }
10668  }
10669 
10670  NextTrackElementPtr = TrackVector.begin();
10671  while(ReturnNextTrackElement(1, Next))
10672  {
10673  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10674  {
10675  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10676  {
10677  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10678  {
10679  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10680  }
10681  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10682  {
10683  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10684  }
10685  }
10686  else
10687  {
10688  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10689  }
10690  }
10691  }
10692  Disp->Update();
10693  Utilities->CallLogPop(640);
10694 }
10695 
10696 // ---------------------------------------------------------------------------
10697 
10698 void TTrack::PlotSmallRedGap(int Caller)
10699 {
10700  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10702  Utilities->CallLogPop(1346);
10703 }
10704 
10705 // ---------------------------------------------------------------------------
10706 
10707 void TTrack::TrackClear(int Caller)
10708 {
10709  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10710  TrackVector.clear();
10711  InactiveTrackVector.clear();
10712  TrackMap.clear();
10714  if(TextHandler->TextVector.size() == 0)
10715  {
10716  Display->DisplayOffsetH = 0;
10717  Display->DisplayOffsetV = 0;
10724  HLocMin = 2000000000;
10725  HLocMax = -2000000000;
10726  VLocMin = 2000000000;
10727  VLocMax = -2000000000;
10728  }
10729  else
10730  {
10731  CalcHLocMinEtc(4);
10732  }
10733  Utilities->CallLogPop(1347);
10734 }
10735 
10736 // ---------------------------------------------------------------------------
10737 
10738 void TTrack::CalcHLocMinEtc(int Caller)
10739 {
10740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10741  HLocMin = 2000000000;
10742  VLocMin = 2000000000;
10743  HLocMax = -2000000000;
10744  VLocMax = -2000000000;
10745  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10746  {
10747  if(TrackElementAt(1385, x).SpeedTag == 0)
10748  {
10749  continue; // skip erase elements or would interfere with Min & Max values
10750  }
10751  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10752  {
10753  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10754  }
10755  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10756  {
10757  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10758  }
10759  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10760  {
10761  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10762  }
10763  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10764  {
10765  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10766  }
10767  }
10768  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10769  {
10770  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10771  {
10772  continue; // shouldn't be any inactive erase elements but include anyway
10773  }
10774  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10775  {
10776  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10777  }
10778  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10779  {
10780  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10781  }
10782  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10783  {
10784  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10785  }
10786  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10787  {
10788  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10789  }
10790  }
10791  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10792  {
10793 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10794  will fail as x will exceed the maximum value
10795  if(TextHandler->TextPtrAt(, x)->TextString == "")
10796  {
10797  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10798  }
10799 */
10800  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10801  if((TextH / 16) - 1 < HLocMin)
10802  {
10803  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10804  }
10805  if((TextH / 16) + 1 > HLocMax)
10806  {
10807  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10808  }
10809  if((TextV / 16) - 1 < VLocMin)
10810  {
10811  VLocMin = (TextV / 16) - 1;
10812  }
10813  if((TextV / 16) + 1 > VLocMax)
10814  {
10815  VLocMax = (TextV / 16) + 1;
10816  }
10817  }
10818  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10819  {
10820  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10821  {
10822  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10823  }
10824  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10825  {
10826  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10827  }
10828  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10829  {
10830  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10831  }
10832  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10833  {
10834  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10835  }
10836  }
10837 
10838  Utilities->CallLogPop(641);
10839 }
10840 
10841 // ---------------------------------------------------------------------------
10842 
10843 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10844  bool &UserGraphicFoundFlag)
10845 {
10846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10847  TUserGraphicVector::iterator UserGraphicPtr;
10848 
10849  UserGraphicFoundFlag = false;
10850  if(!UserGraphicVector.empty())
10851  {
10852  int x = UserGraphicVector.size();
10853  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10854  {
10855  x--;
10856  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10857  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10858  {
10859  UserGraphicItem = x;
10860  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10861  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10862  UserGraphicFoundFlag = true;
10863  Utilities->CallLogPop(2177);
10864  return;
10865  } // if ....
10866 
10867  } // for UserGraphicPtr...
10868  } // if !UserGraphicVector...
10869 
10870  Utilities->CallLogPop(2197);
10871 }
10872 
10873 // ---------------------------------------------------------------------------
10874 
10876 {
10877  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10878  TrackElement.LogTrack(11));
10879  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10880  int SpeedTag = TrackElement.SpeedTag;
10881 
10882  if(SpeedTag < 1)
10883  {
10884  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10885  }
10886  switch(SpeedTag)
10887  {
10888  case 76: // t platform
10889  GraphicOutput = RailGraphics->gl76Striped;
10890  break;
10891 
10892  case 77: // h platform
10893  GraphicOutput = RailGraphics->bm77Striped;
10894  break;
10895 
10896  case 78: // v platform
10897  GraphicOutput = RailGraphics->bm78Striped;
10898  break;
10899 
10900  case 79: // r platform
10901  GraphicOutput = RailGraphics->gl79Striped;
10902  break;
10903 
10904  case 96: // concourse
10905  GraphicOutput = RailGraphics->ConcourseStriped;
10906  break;
10907 
10908  case 129: // v footbridge
10909  GraphicOutput = RailGraphics->gl129Striped;
10910  break;
10911 
10912  case 130: // h footbridge
10913  GraphicOutput = RailGraphics->gl130Striped;
10914  break;
10915 
10916  case 131: // non-station named loc
10917  GraphicOutput = RailGraphics->bmNameStriped;
10918  break;
10919 
10920  case 145: // v u'pass
10921  GraphicOutput = RailGraphics->gl145Striped;
10922  break;
10923 
10924  case 146: // h u'pass
10925  GraphicOutput = RailGraphics->gl146Striped;
10926  break;
10927 
10928  default:
10929  GraphicOutput = TrackElement.GraphicPtr;
10930  break;
10931  }
10932  Utilities->CallLogPop(642);
10933  return(GraphicOutput);
10934 }
10935 
10936 // ---------------------------------------------------------------------------
10937 
10939 {
10940  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10941  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10942  {
10943 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
10944  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10945  }
10946  Utilities->CallLogPop(643);
10947  return(TrackVector.at(At));
10948 }
10949 
10950 // ---------------------------------------------------------------------------
10951 
10953 {
10954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10955  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10956  {
10957  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10958  " in InactiveTrackElementAt");
10959  }
10960  Utilities->CallLogPop(644);
10961  return(InactiveTrackVector.at(At));
10962 }
10963 
10964 // ---------------------------------------------------------------------------
10965 
10966 bool TTrack::BlankElementAt(int Caller, int At) const
10967 {
10968  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10969  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10970  {
10971  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10972  }
10973  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10974  {
10975  Utilities->CallLogPop(645);
10976  return(true);
10977  }
10978  else
10979  {
10980  Utilities->CallLogPop(646);
10981  return(false);
10982  }
10983 }
10984 
10985 // ---------------------------------------------------------------------------
10986 
10987 bool TTrack::OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
10988 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10989  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10990  split is required a specific check is made using ThisStationLongEnoughForSplit.
10991  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10992  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10993 */
10994 {
10995  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneStationLongEnoughForSplit," + LocationName);
10996  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10997  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10998  TLocationNameMultiMapIterator SNIterator;
10999  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11000 
11001  if(SNRange.first == SNRange.second)
11002  {
11003  Utilities->CallLogPop(972);
11004  return(false); // should have been caught earlier but include for completeness
11005  }
11006  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11007  {
11008  if(SNIterator->second < 0)
11009  {
11010  continue; // exclude footcrossings
11011  }
11012  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
11013  if(InactiveElement.TrackType == Concourse)
11014  {
11015  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11016  }
11017  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11018  {
11019  continue; // only interested in locations where ActiveTrackElementName may be set
11020  }
11021  THVPair HVPair;
11022  HVPair.first = InactiveElement.HLoc;
11023  HVPair.second = InactiveElement.VLoc;
11024  if(TrackMap.find(HVPair) == TrackMap.end())
11025  {
11026  throw Exception
11027  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneStationLongEnoughForSplit (1)");
11028  }
11029  int TVPos = TrackMap.find(HVPair)->second;
11030  FirstNamedElement = TrackElementAt(560, TVPos);
11031  // first check linked on both sides, skip the check if not
11032  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
11033  {
11034  continue;
11035  }
11036  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
11037  // ActiveTrackElementNames are points and excluding trailing connections for points
11038  FirstNamedExitPos = 0;
11039  {
11040  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
11041  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11042  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11043  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11044  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11045  {
11046  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11047  {
11048  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
11049  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11050  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11051  // success, now check FirstNamedElement link not trailing points & if so all OK
11052  {
11053  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11054  {
11055  Utilities->CallLogPop(1002);
11056  return(true);
11057  }
11058  }
11059  }
11060  }
11061  }
11062  // failed, try link 1
11063  FirstNamedExitPos = 1;
11064  {
11065  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
11066  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11067  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11068  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11069  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11070  {
11071  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11072  {
11073  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
11074  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11075  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11076  // success, now check FirstNamedElement link not trailing points & if so all OK
11077  {
11078  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11079  {
11080  Utilities->CallLogPop(1003);
11081  return(true);
11082  }
11083  }
11084  }
11085  }
11086  }
11087  }
11088  Utilities->CallLogPop(1004);
11089  return(false);
11090 }
11091 
11092 // ---------------------------------------------------------------------------
11093 
11094 bool TTrack::OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName) //changed at v2.18.0
11095 /* Check sufficient active elements at same H & V as the non-station element with same ActiveTrackElementName linked together to allow a train split.
11096  Only one train length is needed to return true, but this doesn't mean that all tracks at the location are long enough. When a
11097  split is required a specific check is made using ThisLocationLongEnoughForSplit.
11098  Need at least two linked ActiveTrackElementNames, with connected elements at each end, or three if one end is a buffer, but no need to check
11099  buffers explicitly as it will come out automatically with the logic applied.
11100  Note that these conditions exclude opposed buffers since these not linked.
11101 */
11102 {
11103  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNonStationLongEnoughForSplit," + LocationName);
11104  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11105  int FirstNamedExitPos, SecondNamedEntryPos, SecondNamedExitPos;
11106  TLocationNameMultiMapIterator SNIterator;
11107  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11108 
11109  if(SNRange.first == SNRange.second)
11110  {
11111  Utilities->CallLogPop(2641);
11112  return(false); // should have been caught earlier but include for completeness
11113  }
11114  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11115  {
11116  if(SNIterator->second < 0) //negative numbers represent active track elements
11117  {
11118  continue; // exclude footcrossings - only these have active track element names
11119  }
11120  InactiveElement = InactiveTrackElementAt(1412, SNIterator->second);
11121  if(InactiveElement.TrackType == Concourse)
11122  {
11123  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11124  }
11125  if(!TrackElementPresentAtHV(2, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11126  {
11127  continue; // only interested in locations where ActiveTrackElementName may be set
11128  }
11129  THVPair HVPair;
11130  HVPair.first = InactiveElement.HLoc;
11131  HVPair.second = InactiveElement.VLoc;
11132  if(TrackMap.find(HVPair) == TrackMap.end())
11133  {
11134  throw Exception ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNonStationLongEnoughForSplit(1)");
11135  }
11136  int TVPos = TrackMap.find(HVPair)->second;
11137  FirstNamedElement = TrackElementAt(1610, TVPos);
11138  // first check linked on both sides, skip the check if not
11139  if(((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) && ((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)))
11140  {
11141  continue;
11142  }
11143  // check if another ActiveTrackElementName connected via a link
11144  if((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)) //examine connections at links 0 & 1
11145  {
11146  FirstNamedExitPos = 0; //this is the end linked to the second named element
11147  {
11148  SecondNamedElement = TrackElementAt(1611, FirstNamedElement.Conn[FirstNamedExitPos]);
11149  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11150  {
11151  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11152  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11153  {
11154  SecondNamedExitPos = 1 - SecondNamedEntryPos; //SecondNamedExitPos is the end not linked to FirstNamedElement
11155  }
11156  else if(SecondNamedEntryPos == 2)
11157  {
11158  SecondNamedExitPos = 3;
11159  }
11160  else if(SecondNamedEntryPos == 3)
11161  {
11162  SecondNamedExitPos = 2;
11163  }
11164  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11165  {
11166  Utilities->CallLogPop(2642);
11167  return(true);
11168  } //if not try other exitpos
11169  }
11170  }
11171  FirstNamedExitPos = 1;
11172  {
11173  SecondNamedElement = TrackElementAt(1612, FirstNamedElement.Conn[FirstNamedExitPos]);
11174  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11175  {
11176  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11177  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11178  {
11179  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11180  }
11181  else if(SecondNamedEntryPos == 2)
11182  {
11183  SecondNamedExitPos = 3;
11184  }
11185  else if(SecondNamedEntryPos == 3)
11186  {
11187  SecondNamedExitPos = 2;
11188  }
11189  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11190  {
11191  Utilities->CallLogPop(2643);
11192  return(true);
11193  } //failed so far, try links 2 & 3, one or other must be linked on both side or would have continued
11194  }
11195  }
11196  }
11197  else if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) //examine connections at links 2 & 3
11198  {
11199  FirstNamedExitPos = 2;
11200  {
11201  SecondNamedElement = TrackElementAt(1613, FirstNamedElement.Conn[FirstNamedExitPos]);
11202  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11203  {
11204  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11205  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11206  {
11207  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11208  }
11209  else if(SecondNamedEntryPos == 2)
11210  {
11211  SecondNamedExitPos = 3;
11212  }
11213  else if(SecondNamedEntryPos == 3)
11214  {
11215  SecondNamedExitPos = 2;
11216  }
11217  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11218  {
11219  Utilities->CallLogPop(2644);
11220  return(true);
11221  } //if not try other exitpos
11222  }
11223  }
11224  FirstNamedExitPos = 3;
11225  {
11226  SecondNamedElement = TrackElementAt(1614, FirstNamedElement.Conn[FirstNamedExitPos]);
11227  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11228  {
11229  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11230  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11231  {
11232  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11233  }
11234  else if(SecondNamedEntryPos == 2)
11235  {
11236  SecondNamedExitPos = 3;
11237  }
11238  else if(SecondNamedEntryPos == 3)
11239  {
11240  SecondNamedExitPos = 2;
11241  }
11242  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11243  {
11244  Utilities->CallLogPop(2645);
11245  return(true);
11246  } //failed so continue to next element or return false
11247  }
11248  }
11249  }
11250  }
11251  Utilities->CallLogPop(2646);
11252  return(false);
11253 }
11254 
11255 // ---------------------------------------------------------------------------
11256 
11257 //new version at v2.18.0
11258 bool TTrack::ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement,
11259  int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
11260 /* Return false if the track that the train is on isn't long enough for a split - only 1 named element or 2 with only one external link.
11261 Otherwise find the best 4 final element positions, preferably with FrontTrainFrontPos on a named element. Conditions are that the original train
11262 will lie within the 4 elements of the two split trains, and at least 1 element of each split train will be at the location. Within those conditions
11263 the lead element of the front train will be at the location if it is possible.
11264 */
11265 {
11266  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisLocationLongEnoughForSplit," + AnsiString(TrainID) + "," +
11267  LocationName + AnsiString(LeadElement) + "," + AnsiString(LeadExitPos) + "," + AnsiString(MidElement) + "," + AnsiString(MidEntryPos));
11268 
11269  TemporaryDelay = false; //used in calling function to set LastActionTime to TTClockTime so failure messages only given every 30 secs
11270  //count forwards from LeadElement - only need to count forwards 2 elements to ptovide for room for new front train
11271  int FwdPos[3] = {LeadElement, -1, -1}; //0 starts at LeadElement and increases as go forwards
11272  int RwdPos[3] = {MidElement, -1, -1}; //0 starts at MidElement and increases as go backwards
11273  TTrackElement FwdPos0Element = TrackElementAt(1666, LeadElement);
11274  TTrackElement RwdPos0Element = TrackElementAt(1667, MidElement);
11275  int FwdPos1EntryPos, FwdPos1ExitPos, FwdPos2EntryPos, FwdPos2ExitPos, RwdPos1EntryPos, RwdPos1ExitPos, RwdPos2EntryPos, RwdPos2ExitPos; //these needed to test for other train on element
11276 
11277  bool FwdDerail1 = false, FwdDerail2 = false, RwdDerail1 = false, RwdDerail2 = false;
11278  int NumFwdNamedElements = 0, NumFwdElements = 0, NumRwdNamedElements = 0, NumRwdElements = 1; //Fwd = ahead of LeadElement, Rwd includes MidElement
11279  if(RwdPos0Element.ActiveTrackElementName == LocationName) //MidElement
11280  {
11281  NumRwdNamedElements = 1;
11282  }
11283 
11284  FwdPos[1] = FwdPos0Element.Conn[LeadExitPos];
11285  if(FwdPos[1] > -1)
11286  {
11287  NumFwdElements = 1;
11288  TTrackElement FwdPos1Element = TrackElementAt(1668, FwdPos[1]);
11289  if(FwdPos1Element.ActiveTrackElementName == LocationName)
11290  {
11291  NumFwdNamedElements = 1;
11292  }
11293  FwdPos1EntryPos = FwdPos0Element.ConnLinkPos[LeadExitPos];
11294  FwdPos1ExitPos = GetAnyElementOppositeLinkPos(4, FwdPos[1], FwdPos1EntryPos, FwdDerail1);
11295  FwdPos[2] = FwdPos1Element.Conn[FwdPos1ExitPos];
11296  if(FwdPos[2] > -1)
11297  {
11298  NumFwdElements = 2;
11299  FwdPos2EntryPos = FwdPos1Element.ConnLinkPos[FwdPos1ExitPos];
11300  FwdPos2ExitPos = GetAnyElementOppositeLinkPos(5, FwdPos[2], FwdPos2EntryPos, FwdDerail2); //this is purely to obtain Derail
11301  TTrackElement FwdPos2Element = TrackElementAt(1669, FwdPos[2]);
11302  if(FwdPos2Element.ActiveTrackElementName == LocationName)
11303  {
11304  NumFwdNamedElements = 2;
11305  }
11306  }
11307  }
11308 //this is as far as need to go forwards
11309 
11310  RwdPos[1] = RwdPos0Element.Conn[MidEntryPos];
11311  if(RwdPos[1] > -1)
11312  {
11313  NumRwdElements = 2; //includes MidElement
11314  TTrackElement RwdPos1Element = TrackElementAt(1670, RwdPos[1]);
11315  if(RwdPos1Element.ActiveTrackElementName == LocationName)
11316  {
11317  NumRwdNamedElements = 2; //includes MidElement (treats MidElement as named even if not, as eventual positions will be same either way)
11318  }
11319  RwdPos1ExitPos = RwdPos0Element.ConnLinkPos[MidEntryPos];
11320  RwdPos1EntryPos = GetAnyElementOppositeLinkPos(6, RwdPos[1], RwdPos1ExitPos, RwdDerail1);
11321  RwdPos[2] = RwdPos1Element.Conn[RwdPos1EntryPos];
11322  if(RwdPos[2] > -1)
11323  {
11324  NumRwdElements = 3; //includes MidElement
11325  RwdPos2ExitPos = RwdPos1Element.ConnLinkPos[RwdPos1EntryPos];
11326  RwdPos2EntryPos = GetAnyElementOppositeLinkPos(7, RwdPos[2], RwdPos2ExitPos, RwdDerail2); //this is purely to obtain Derail
11327  TTrackElement RwdPos2Element = TrackElementAt(1671, RwdPos[2]);
11328  if(RwdPos2Element.ActiveTrackElementName == LocationName)
11329  {
11330  NumRwdNamedElements = 3; //includes MidElement (treats MidElement & next position to rear as both named even if not, as eventual positions will be same either way)
11331  }
11332  }
11333  }
11334 //this is as far as need to go backwards
11335 
11336 //now try to accommodate front train on named elements if possible
11337  if(NumFwdNamedElements == 2)//Front train moves onto the 2 forward named elements & rear train is on original train elements X N N N (N = named, X = named or not)
11338  { // M L - - >> RM RL FM FL
11339  FrontTrainFrontPos = FwdPos[2];
11340  FrontTrainRearPos = FwdPos[1];
11341  RearTrainFrontPos = LeadElement;
11342  RearTrainRearPos = MidElement;
11343  if(FwdDerail1 || FwdDerail2)
11344  {
11345  TrainController->StopTTClockMessage(159, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11346  TemporaryDelay = true;
11347  Utilities->CallLogPop(2661); //may be able to split further back but leave as is to avoid complication
11348  return(true);
11349  }
11350  if(OtherTrainOnTrack(6, FwdPos[1], FwdPos1EntryPos, TrainID))
11351  {
11352  TrainController->StopTTClockMessage(160, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11353  TemporaryDelay = true;
11354  Utilities->CallLogPop(2662); //may be able to split further back but leave as is to avoid complication
11355  return(true);
11356  }
11357  if(OtherTrainOnTrack(7, FwdPos[2], FwdPos2ExitPos, TrainID))
11358  {
11359  TrainController->StopTTClockMessage(161, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11360  TemporaryDelay = true;
11361  Utilities->CallLogPop(2663); //may be able to split further back but leave as is to avoid complication
11362  return(true);
11363  }
11364  Utilities->CallLogPop(2664);
11365  return(true);
11366  }
11367 
11368  else if((NumFwdNamedElements == 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11369  { //Front train moves onto the 1 forward named element & rear train occupies 1 element behind original train - M L - >> RM RL FM FL
11370  FrontTrainFrontPos = FwdPos[1];
11371  FrontTrainRearPos = LeadElement;
11372  RearTrainFrontPos = MidElement;
11373  RearTrainRearPos = RwdPos[1];
11374  if(FwdDerail1)
11375  {
11376  TrainController->StopTTClockMessage(162, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11377  TemporaryDelay = true;
11378  Utilities->CallLogPop(2665); //may be able to split further back but leave as is to avoid complication
11379  return(true);
11380  }
11381  if(RwdDerail1)
11382  {
11383  TrainController->StopTTClockMessage(163, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11384  TemporaryDelay = true;
11385  Utilities->CallLogPop(2666); //may be able to split further back but leave as is to avoid complication
11386  return(true);
11387  }
11388  if(OtherTrainOnTrack(8, FwdPos[1], FwdPos1EntryPos, TrainID))
11389  {
11390  TrainController->StopTTClockMessage(164, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11391  TemporaryDelay = true;
11392  Utilities->CallLogPop(2667); //may be able to split further back but leave as is to avoid complication
11393  return(true);
11394  }
11395  if(OtherTrainOnTrack(9, RwdPos[1], RwdPos1ExitPos, TrainID))
11396  {
11397  TrainController->StopTTClockMessage(165, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11398  TemporaryDelay = true;
11399  Utilities->CallLogPop(2668); //may be able to split further back but leave as is to avoid complication
11400  return(true);
11401  }
11402  Utilities->CallLogPop(2669);
11403  return(true);
11404  }
11405 
11406  else if((NumRwdNamedElements >= 2) && (NumRwdElements == 3)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11407  {//front train occupies original train position and rear train fits behind it - - M L >> RM RL FM FL
11408  FrontTrainFrontPos = LeadElement;
11409  FrontTrainRearPos = MidElement;
11410  RearTrainFrontPos = RwdPos[1];
11411  RearTrainRearPos = RwdPos[2];
11412  if(RwdDerail1 || RwdDerail2)
11413  {
11414  TrainController->StopTTClockMessage(166, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11415  TemporaryDelay = true;
11416  Utilities->CallLogPop(2670); //may be able to split further back but leave as is to avoid complication
11417  return(true);
11418  }
11419  if(OtherTrainOnTrack(10, RwdPos[1], RwdPos1ExitPos, TrainID))
11420  {
11421  TrainController->StopTTClockMessage(167, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11422  TemporaryDelay = true;
11423  Utilities->CallLogPop(2671); //may be able to split further back but leave as is to avoid complication
11424  return(true);
11425  }
11426  if(OtherTrainOnTrack(11, RwdPos[2], RwdPos2EntryPos, TrainID))
11427  {
11428  TrainController->StopTTClockMessage(168, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11429  TemporaryDelay = true;
11430  Utilities->CallLogPop(2672); //may be able to split further back but leave as is to avoid complication
11431  return(true);
11432  }
11433  Utilities->CallLogPop(2673);
11434  return(true);
11435  }
11436 
11437 //here look for front overhang situations
11438  else if((NumFwdNamedElements == 1) && (NumFwdElements == 2)) // X N N X (N = named, X = named or not but connected)
11439  { // M L - - >> RM RL FM FL
11440  FrontTrainFrontPos = FwdPos[2];
11441  FrontTrainRearPos = FwdPos[1];
11442  RearTrainFrontPos = LeadElement;
11443  RearTrainRearPos = MidElement;
11444  if(FwdDerail1 || FwdDerail2)
11445  {
11446  TrainController->StopTTClockMessage(169, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11447  TemporaryDelay = true;
11448  Utilities->CallLogPop(2674); //may be able to split further back but leave as is to avoid complication
11449  return(true);
11450  }
11451  if(OtherTrainOnTrack(12, FwdPos[1], FwdPos1EntryPos, TrainID))
11452  {
11453  TrainController->StopTTClockMessage(170, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11454  TemporaryDelay = true;
11455  Utilities->CallLogPop(2675); //may be able to split further back but leave as is to avoid complication
11456  return(true);
11457  }
11458  if(OtherTrainOnTrack(13, FwdPos[2], FwdPos2ExitPos, TrainID))
11459  {
11460  TrainController->StopTTClockMessage(171, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11461  TemporaryDelay = true;
11462  Utilities->CallLogPop(2676); //may be able to split further back but leave as is to avoid complication
11463  return(true);
11464  }
11465  Utilities->CallLogPop(2677);
11466  return(true);
11467  }
11468 
11469  else if((NumFwdElements >= 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) // X N N X (N = named, X = named or not but connected)
11470  { // - M L - >> RM RL FM FL
11471  FrontTrainFrontPos = FwdPos[1];
11472  FrontTrainRearPos = LeadElement;
11473  RearTrainFrontPos = MidElement;
11474  RearTrainRearPos = RwdPos[1];
11475  if(FwdDerail1)
11476  {
11477  TrainController->StopTTClockMessage(172, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11478  TemporaryDelay = true;
11479  Utilities->CallLogPop(2678); //may be able to split further back but leave as is to avoid complication
11480  return(true);
11481  }
11482  if(RwdDerail1)
11483  {
11484  TrainController->StopTTClockMessage(173, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11485  TemporaryDelay = true;
11486  Utilities->CallLogPop(2679); //may be able to split further back but leave as is to avoid complication
11487  return(true);
11488  }
11489  if(OtherTrainOnTrack(14, FwdPos[1], FwdPos1EntryPos, TrainID))
11490  {
11491  TrainController->StopTTClockMessage(174, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11492  TemporaryDelay = true;
11493  Utilities->CallLogPop(2680); //may be able to split further back but leave as is to avoid complication
11494  return(true);
11495  }
11496  if(OtherTrainOnTrack(15, RwdPos[1], RwdPos1ExitPos, TrainID))
11497  {
11498  TrainController->StopTTClockMessage(175, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11499  TemporaryDelay = true;
11500  Utilities->CallLogPop(2681); //may be able to split further back but leave as is to avoid complication
11501  return(true);
11502  }
11503  Utilities->CallLogPop(2682);
11504  return(true);
11505  }
11506 //anything else fails as location too short
11507  Utilities->CallLogPop(2652);
11508  return(false);
11509 }
11510 
11511 // ---------------------------------------------------------------------------
11512 
11513 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
11514 {
11515  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
11516  TLocationNameMultiMapIterator SNIterator;
11517  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11518 
11519  if(SNRange.first != SNRange.second)
11520  {
11521  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11522  {
11523  if(SNIterator->second < 0)
11524  {
11525  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
11526  }
11527  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
11528  SNIterator->second).TrackType == NamedNonStationLocation))
11529  {
11530  Utilities->CallLogPop(1121);
11531  return(true);
11532  }
11533  }
11534  }
11535  Utilities->CallLogPop(848);
11536  return(false);
11537 }
11538 
11539 // ---------------------------------------------------------------------------
11540 
11541 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11542 {
11543 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11544  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11545  "," + AnsiString(SpeedTag));
11546  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11547  {
11548  Utilities->CallLogPop(949);
11549  return(false);
11550  }
11551  bool FoundFlag;
11552  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11553 
11554  if(!FoundFlag)
11555  {
11556  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11557  }
11558  TTrackElement IAElement;
11559 
11560  if(SpeedTag == 68) // top sig
11561  {
11562  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11563  {
11564  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11565  {
11566  IAElement = InactiveTrackElementAt(50, IMPair.first);
11567  }
11568  else
11569  {
11570  IAElement = InactiveTrackElementAt(51, IMPair.second);
11571  }
11572  if(IAElement.LocationName == "")
11573  {
11574 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11575  SignalPlatformGraphic = RailGraphics->gl76Striped;
11576  }
11577  else
11578  {
11579 // SignalPlatformGraphic = RailGraphics->Plat68;
11580  SignalPlatformGraphic = RailGraphics->gl76;
11581  }
11582  Utilities->CallLogPop(950);
11583  return(true);
11584  }
11585  }
11586  else if(SpeedTag == 69) // bot sig
11587  {
11588  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11589  {
11590  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11591  {
11592  IAElement = InactiveTrackElementAt(77, IMPair.first);
11593  }
11594  else
11595  {
11596  IAElement = InactiveTrackElementAt(78, IMPair.second);
11597  }
11598  if(IAElement.LocationName == "")
11599  {
11600 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11601  SignalPlatformGraphic = RailGraphics->bm77Striped;
11602  }
11603  else
11604  {
11605 // SignalPlatformGraphic = RailGraphics->Plat69;
11606  SignalPlatformGraphic = RailGraphics->bm77;
11607  }
11608  Utilities->CallLogPop(951);
11609  return(true);
11610  }
11611  }
11612  else if(SpeedTag == 70) // left sig
11613  {
11614  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11615  {
11616  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11617  {
11618  IAElement = InactiveTrackElementAt(55, IMPair.first);
11619  }
11620  else
11621  {
11622  IAElement = InactiveTrackElementAt(82, IMPair.second);
11623  }
11624  if(IAElement.LocationName == "")
11625  {
11626 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11627  SignalPlatformGraphic = RailGraphics->bm78Striped;
11628  }
11629  else
11630  {
11631 // SignalPlatformGraphic = RailGraphics->Plat70;
11632  SignalPlatformGraphic = RailGraphics->bm78;
11633  }
11634  Utilities->CallLogPop(952);
11635  return(true);
11636  }
11637  }
11638  else if(SpeedTag == 71) // right sig
11639  {
11640  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
11641  {
11642  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
11643  {
11644  IAElement = InactiveTrackElementAt(85, IMPair.first);
11645  }
11646  else
11647  {
11648  IAElement = InactiveTrackElementAt(86, IMPair.second);
11649  }
11650  if(IAElement.LocationName == "")
11651  {
11652 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
11653  SignalPlatformGraphic = RailGraphics->gl79Striped;
11654  }
11655  else
11656  {
11657 // SignalPlatformGraphic = RailGraphics->Plat71;
11658  SignalPlatformGraphic = RailGraphics->gl79;
11659  }
11660  Utilities->CallLogPop(953);
11661  return(true);
11662  }
11663  }
11664  Utilities->CallLogPop(954);
11665  return(false);
11666 }
11667 
11668 // ---------------------------------------------------------------------------
11669 
11670 bool TTrack::OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
11671 // returns true if another train on LinkPos track of element at TrackPos, whether bridge or not, return false if not, or if TrackPos == -1,
11672 // or LinkPos == -1, or if only own train on the track. LinkPos can be entry or exit.
11673 {
11674  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(TrackPos) + "," +
11675  AnsiString(LinkPos) + "," + AnsiString(OwnTrainID));
11676  if((LinkPos < 0) || (TrackPos < 0))
11677  {
11678  Utilities->CallLogPop(1348);
11679  return(false);
11680  }
11681  TTrackElement TrackElement = TrackElementAt(713, TrackPos);
11682 
11683  if(TrackElement.TrackType != Bridge)
11684  {
11685  Utilities->CallLogPop(1349);
11686  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
11687  }
11688 // bridge if reach here
11689  if(LinkPos > 1)
11690  {
11691  Utilities->CallLogPop(1350);
11692  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
11693  }
11694  else
11695  {
11696  Utilities->CallLogPop(1351);
11697  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
11698  }
11699 }
11700 
11701 // ---------------------------------------------------------------------------
11702 
11704 {
11705  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
11706  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
11707  {
11708  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
11709  }
11710  Utilities->CallLogPop(1483);
11711  return(SelectVector.at(At));
11712 }
11713 
11714 // ---------------------------------------------------------------------------
11715 
11716 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
11717 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
11718 {
11719  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
11720  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
11721  bool FoundFlag = false;
11722  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
11723  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
11724 
11725  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
11726  Utilities->CallLogPop(1538);
11727  return(FoundFlag);
11728 }
11729 
11730 // ---------------------------------------------------------------------------
11731 
11732 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
11733 {
11734 // return true if find an inactive element called 'Name'
11735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
11736  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
11737  bool FoundFlag = false;
11738 
11739  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11740  {
11741  if(InactiveTrackElementAt(158, x).LocationName == Name)
11742  {
11743  FoundFlag = true;
11744  int V = InactiveTrackElementAt(159, x).VLoc;
11745  int H = InactiveTrackElementAt(160, x).HLoc;
11746  if(V > VLocHi)
11747  {
11748  VLocHi = V;
11749  }
11750  if(V < VLocLo)
11751  {
11752  VLocLo = V;
11753  }
11754  if(H < HLoc)
11755  {
11756  HLoc = H;
11757  }
11758  }
11759  }
11760  if(FoundFlag)
11761  {
11762  VPosHi = 16 * VLocHi;
11763  VPosLo = 16 * VLocLo;
11764  HPos = 16 * HLoc;
11765  Utilities->CallLogPop(1562);
11766  return(true);
11767  }
11768  else
11769  {
11770  Utilities->CallLogPop(1563);
11771  return(false);
11772  }
11773 }
11774 
11775 // ---------------------------------------------------------------------------
11776 
11777 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
11778 {
11779 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
11780 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
11781  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
11782  AnsiString(EndTVPosition));
11783  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
11784  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
11785 
11786 // get H & V values for the element adjacent to Link[0] & Link[1]
11787  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
11788  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
11789  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
11790  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
11791 
11792 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
11793  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
11794  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
11795  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
11796  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
11797 
11798  if(Link0Squares <= Link1Squares)
11799  {
11800  Utilities->CallLogPop(1851);
11801  return(0);
11802  }
11803  else
11804  {
11805  Utilities->CallLogPop(1852);
11806  return(1);
11807  }
11808 }
11809 
11810 // ---------------------------------------------------------------------------
11811 
11812 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11813 {
11814  // element can be points or any other type
11815  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11816  AnsiString(LinkPos));
11817  Derail = false;
11818  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11819 
11820  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11821  {
11822  if(TE.Attribute == 0)
11823  {
11824  Utilities->CallLogPop(663);
11825  return(1); // Att == 0 & ExitPos == 1 represent straight
11826  }
11827  else
11828  {
11829  Utilities->CallLogPop(664);
11830  return(3); // Att == 1 & ExitPos == 3 represent diverging
11831  }
11832  }
11833  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11834  {
11835  if((LinkPos == 1) && (TE.Attribute == 0))
11836  {
11837  Utilities->CallLogPop(665);
11838  return(0); // Att == 0 represents straight
11839  }
11840  else if(LinkPos == 1)
11841  {
11842  Derail = true;
11843  Utilities->CallLogPop(666);
11844  return(0);
11845  }
11846  else if((LinkPos == 3) && (TE.Attribute == 1))
11847  {
11848  Utilities->CallLogPop(667);
11849  return(0);
11850  }
11851  else if(LinkPos == 3)
11852  {
11853  Derail = true;
11854  Utilities->CallLogPop(668);
11855  return(0);
11856  }
11857  }
11858  else if(LinkPos == 0)
11859  {
11860  Utilities->CallLogPop(669);
11861  return(1);
11862  }
11863  else if(LinkPos == 1)
11864  {
11865  Utilities->CallLogPop(670);
11866  return(0);
11867  }
11868  else if(LinkPos == 2)
11869  {
11870  Utilities->CallLogPop(671);
11871  return(3);
11872  }
11873  else if(LinkPos == 3)
11874  {
11875  Utilities->CallLogPop(672);
11876  return(2);
11877  }
11878  throw Exception("Error, failure in GetExitPos"); // should never reach here
11879 }
11880 
11881 // ----------------------------------------------------------------------------
11882 
11884 {
11885  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11886  LCVector.clear();
11887  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11888  {
11889  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11890  {
11891  LCVector.push_back(x);
11892  }
11893  }
11894  Utilities->CallLogPop(1931);
11895  return;
11896 }
11897 
11898 // ---------------------------------------------------------------------------
11899 
11900 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11901 /*
11902  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11903  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11904  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11905  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11906 */
11907 {
11908  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11909  AnsiString(Link));
11910  bool FoundFlag;
11911 
11912  TrainID = -1;
11913  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11914 
11915  if(!FoundFlag)
11916  {
11917  Utilities->CallLogPop(2001);
11918  return(false);
11919  }
11920  TTrackElement TE = TrackElementAt(882, VecPos);
11921 
11922  TrainID = TE.TrainIDOnElement;
11923  if(TE.TrackType == Bridge)
11924  {
11925  if(TE.TrainIDOnElement > -1)
11926  {
11927  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11928  {
11930  }
11931  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11932  {
11934  }
11935  else
11936  {
11937  TrainID = -1; // shouldn't ever reach here but be safe
11938  }
11939  }
11940  }
11941  if(TrainID == -1)
11942  {
11943  Utilities->CallLogPop(2002);
11944  return(false);
11945  }
11946 // now get the train
11947  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11948 
11949  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11950  {
11951  Utilities->CallLogPop(2003);
11952  return(true);
11953  }
11954  TrainID = -1;
11955  Utilities->CallLogPop(2004);
11956  return(false);
11957 }
11958 
11959 // ---------------------------------------------------------------------------
11960 
11961 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11962 /* New at v1.2.0
11963  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11964  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11965  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11966  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11967  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11968  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11969  Each of these is examined in turn for each route element in the relevant position.
11970 */
11971 {
11972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11973  "," + AnsiString(DiagonalLinkNumber));
11974  TrainID = -1;
11975  TPrefDirElement TempPrefDirElement;
11976  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11977 
11978  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11979  {
11980  Utilities->CallLogPop(2027);
11981  return(true);
11982  }
11983  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11984  {
11985  Utilities->CallLogPop(2028);
11986  return(true);
11987  }
11988  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11989  {
11990  Utilities->CallLogPop(2029);
11991  return(true);
11992  }
11993  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11994  {
11995  Utilities->CallLogPop(2030);
11996  return(true);
11997  }
11998  Utilities->CallLogPop(2031);
11999  return(false);
12000 }
12001 
12002 // ---------------------------------------------------------------------------
12003 
12004 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
12005 {
12006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
12007  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
12008  TUserGraphicItem UGI;
12009  AnsiString JustFileName = "";
12010 
12011  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
12012  {
12013  UGI = UserGraphicVectorAt(17, x);
12014  int LastDelim = UGI.FileName.LastDelimiter('\\');
12015  if(LastDelim == 0) // can't find it so skip this item
12016  {
12017  continue;
12018  }
12019  else
12020  {
12021  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
12022  }
12023  Utilities->SaveFileString(VecFile, JustFileName);
12024  Utilities->SaveFileInt(VecFile, UGI.HPos);
12025  Utilities->SaveFileInt(VecFile, UGI.VPos);
12026  }
12027  Utilities->CallLogPop(2178);
12028 }
12029 
12030 // ---------------------------------------------------------------------------
12031 
12032 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
12033 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
12034 {
12035  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
12036  int NumPlats = 0;
12037  TTrackElement TempElement;
12038  int TempInt;
12039 
12040  typedef std::list<int> TNamePosList;
12041  TNamePosList NamePosList;
12042  typedef TNamePosList::iterator TNPLIt;
12043  TNPLIt NPLIt;
12044  typedef std::list<int> TOnePlatList;
12045  TOnePlatList OnePlatList;
12046  typedef TOnePlatList::iterator TOPLIt;
12047  TOPLIt OPLIt;
12048 
12049  NamePosList.clear();
12050  OnePlatList.clear();
12051  for(unsigned int x = 0; x < TrackVector.size(); x++)
12052  {
12053  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
12054  {
12055  NamePosList.push_back(x);
12056  }
12057  }
12058  //NamePosList complete
12059 
12060  if(!NamePosList.empty()) //first value for the loop examination
12061  {
12062  OnePlatList.push_back(NamePosList.back());
12063  NamePosList.pop_back(); //erase from NPV as done with it here
12064  }
12065  while(!OnePlatList.empty()) //loop to examine all linked elements
12066  {
12067  TempInt = OnePlatList.front();
12068  TempElement = TrackElementAt(989, TempInt);
12069 
12070  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
12071  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
12072  {
12073  OnePlatList.push_back(TempElement.Conn[0]);
12074  NamePosList.erase(NPLIt);
12075  }
12076  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
12077  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
12078  {
12079  OnePlatList.push_back(TempElement.Conn[1]);
12080  NamePosList.erase(NPLIt);
12081  }
12082  //here when loaded any connecting links into OnePlatList, so can erase the front element
12083  OnePlatList.erase(OnePlatList.begin());
12084  if(OnePlatList.empty())
12085  {
12086  NumPlats++; //finished with current linked elements so can increment NumPlats
12087  if(!NamePosList.empty())
12088  {
12089  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
12090  NamePosList.pop_back(); //erase from NPV as done with it there
12091  }
12092  }
12093  }
12094  Utilities->CallLogPop(2218);
12095  return(NumPlats);
12096 }
12097 
12098 // ---------------------------------------------------------------------------
12099 
12100 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12101 {//repair Signals pointed to by FPVIt
12102  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
12103  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
12104  if(TE.TrackType != SignalPost)
12105  {
12106  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
12107  }
12108  if(!TE.Failed)
12109  {
12110  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
12111  }
12112  TE.Failed = false;
12113  //set to correct aspect
12114  int RouteNumber;
12115  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
12116  { // 0 for LinkPos ok as a signal so only one track
12117  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
12118  }
12119  //erase from vector
12120  Track->FailedSignalsVector.erase(FPVIt);
12121 
12122  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12123  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12124  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
12125  AllRoutes->RebuildRailwayFlag = true;
12126  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
12127  Utilities->CallLogPop(2519);
12128 }
12129 
12130 // ---------------------------------------------------------------------------
12131 
12132 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12133 {//repair points pointed to by FPVIt
12134  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
12135  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
12136  if(TE.TrackType != Points)
12137  {
12138  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
12139  }
12140  if(!TE.Failed)
12141  {
12142  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
12143  }
12144  TE.Failed = false;
12149  //erase from vector
12150  Track->FailedPointsVector.erase(FPVIt);
12151 
12152  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12153  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12154  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
12155  AllRoutes->RebuildRailwayFlag = true;
12156  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12157  Utilities->CallLogPop(2518);
12158 }
12159 
12160 // ---------------------------------------------------------------------------
12161 
12162 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12163 {//repair TSR pointed to by FPVIt
12164  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
12165  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
12166  if(TE.TrackType != Simple)
12167  {
12168  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
12169  }
12170  if(!TE.Failed)
12171  {
12172  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
12173  }
12174  TE.Failed = false;
12177  //erase from vector
12178  Track->TSRVector.erase(FPVIt);
12179 
12180  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12181  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12182  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
12183  AllRoutes->RebuildRailwayFlag = true;
12184  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12185  Utilities->CallLogPop(2520);
12186 }
12187 
12188 // ---------------------------------------------------------------------------
12189 
12191 {
12192  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
12193  SimpleVector.clear();
12194  for(unsigned int x = 0; x < TrackVector.size(); x++)
12195  {
12196  if(TrackElementAt(1517, x).TrackType == Simple)
12197  {
12198  SimpleVector.push_back(int(x));
12199  }
12200  }
12201  Utilities->CallLogPop(2521);
12202 }
12203 
12204 // ---------------------------------------------------------------------------
12205 // UserGraphic, PrefDir & Route functions
12206 // ---------------------------------------------------------------------------
12207 
12209 {
12210  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
12211  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
12212  {
12213  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
12214  }
12215  Utilities->CallLogPop(2194);
12216  return(UserGraphicVector.at(At));
12217 }
12218 
12219 // ---------------------------------------------------------------------------
12220 
12221 int TOnePrefDir::LastElementNumber(int Caller) const
12222 {
12223  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
12224  int RetVal = PrefDirVector.size() - 1;
12225 
12226  if(RetVal < 0)
12227  {
12228  throw Exception("Return value negative in call to LastElementNumber");
12229  }
12230  Utilities->CallLogPop(114);
12231  return(RetVal);
12232 }
12233 
12234 // ---------------------------------------------------------------------------
12236 {
12237  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
12238  if(PrefDirVector.empty())
12239  {
12240  throw Exception("PrefDirVector empty in call to LastElementPtr");
12241  }
12242  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
12243 
12244  Utilities->CallLogPop(115);
12245  return(RetIT);
12246 }
12247 
12248 // ---------------------------------------------------------------------------
12250 {
12251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
12252  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12253  {
12254  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
12255  }
12256  Utilities->CallLogPop(116);
12257  return(PrefDirVector.at(At));
12258 }
12259 
12260 // ---------------------------------------------------------------------------
12262 {
12263  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
12264  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12265  {
12266  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
12267  " in GetModifiablePrefDirElementAt");
12268  }
12269  Utilities->CallLogPop(117);
12270  return(PrefDirVector.at(At));
12271 }
12272 
12273 // ---------------------------------------------------------------------------
12275 {
12276  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
12277  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12278  {
12279  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
12280  }
12281  Utilities->CallLogPop(118);
12282  return(SearchVector.at(At));
12283 }
12284 
12285 // ---------------------------------------------------------------------------
12287 {
12288  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
12289  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12290  {
12291  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
12292  }
12293  Utilities->CallLogPop(119);
12294  return(SearchVector.at(At));
12295 }
12296 
12297 // ---------------------------------------------------------------------------
12298 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
12299 /*
12300  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
12301  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
12302  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
12303  set in later functions.
12304 */
12305 {
12306  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12307  ClearPrefDir();
12308  int TrackVectorPosition;
12309  TTrackElement TrackElement;
12310 
12311  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12312  {
12313  Utilities->CallLogPop(126);
12314  return(false);
12315  }
12316 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
12317  if(TrackElement.TrackType == Points)
12318  {
12319  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
12320  //it isn't known which trailing edge is the required PrefDir - could use the straight as
12321  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
12322  //best to prevent it to avoid problems
12323  Utilities->CallLogPop(127);
12324  return false;
12325  }
12326 */
12327  TPrefDirElement PrefDirElement(TrackElement);
12328 
12329  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
12330  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
12331  StorePrefDirElement(1, PrefDirElement); // enter first element
12332 // Note that ELink not set even if a buffer or continuation - these set in
12333 // ConvertPrefDirSearchVector after 2nd element added
12334 
12335  Utilities->CallLogPop(128);
12336  return(true);
12337 }
12338 
12339 // ---------------------------------------------------------------------------
12340 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
12341 
12342 /*
12343  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
12344  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
12345  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
12346  with setting the PrefDir vector, & return true.
12347  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
12348  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
12349  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
12350  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
12351  ConvertPrefDirSearchVector to set PrefDirVector.
12352  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
12353  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
12354  find the required element return false. CheckCount is used to keep track of set values to allow check later.
12355 */
12356 
12357 {
12358  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12359  FinishElement = false;
12360  int TrackVectorPosition;
12361 
12362  TotalSearchCount = 0;
12363  TTrackElement TrackElement, TempTrackElement;
12364 
12365  if(PrefDirVector.size() == 0)
12366  {
12367  Utilities->CallLogPop(129);
12368  return(false);
12369  }
12370  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12371  {
12372  Utilities->CallLogPop(130);
12373  return(false);
12374  }
12375 // set the search limits using the last stored element in PrefDirVector as the start point
12376 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12377 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12378 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12379 
12380  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
12381 
12382  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
12383  {
12384  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
12385  SearchLimitHighH = TrackElement.HLoc + 15;
12386  }
12387  else
12388  {
12389  SearchLimitLowH = TrackElement.HLoc - 15;
12390  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
12391  }
12392  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
12393  {
12394  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
12395  SearchLimitHighV = TrackElement.VLoc + 15;
12396  }
12397  else
12398  {
12399  SearchLimitLowV = TrackElement.VLoc - 15;
12400  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
12401  }
12402 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
12403  check & TotalSearchCounts check
12404  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
12405  {
12406  ShowMessage("Unable to reach the selected element - too far ahead");
12407  Utilities->CallLogPop(1692);
12408  return false;
12409  }
12410 */
12411 // get last PrefDir element
12412  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
12413  {
12414  // check if TrackElement adjacent to any of the 4 XLinkPos'
12415  for(int x = 0; x < 4; x++)
12416  {
12417  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
12418  {
12419  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
12420  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
12421  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
12422  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
12423  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
12424  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
12425  // shouldn't ever get it in a serious railway though.
12426 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
12427  }
12428  }
12429  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
12430  {
12431  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
12432  SearchVector.clear(); // use this & convert to set all PrefDir element values
12433  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
12434  {
12436  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12437  {
12438  FinishElement = true;
12439  }
12440  Utilities->CallLogPop(131);
12441  return(true);
12442  }
12443  } // not an adjacent element
12444 
12445  // now check each of the 4 possible XLinkPos values
12446  for(int x = 0; x < 4; x++)
12447  {
12448  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
12449  {
12450  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
12451  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
12452  SearchVector.clear();
12453  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
12454  {
12456  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12457  {
12458  FinishElement = true;
12459  }
12460  Utilities->CallLogPop(132);
12461  return(true);
12462  }
12463  }
12464  } // here if checked all possible exits without success
12465  ShowMessage(
12466  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12467  Utilities->CallLogPop(133);
12468  return(false);
12469  }
12470 // dealt above with LastPrefDirElement being the start element (which can be points)
12471 
12472  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
12473  .ELinkPos] == Lead)) // leading point
12474  {
12475  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
12476  {
12477  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
12478  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
12479  // can't be buffers or gap if points
12480  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
12481  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
12482  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
12483  SearchVector.clear();
12484  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
12485  {
12487  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12488  {
12489  FinishElement = true;
12490  }
12491  Utilities->CallLogPop(134);
12492  return(true);
12493  }
12494  }
12495  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
12496  {
12497  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
12498  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
12499  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
12500  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
12501  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
12502  SearchVector.clear();
12503  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
12504  {
12506  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12507  {
12508  FinishElement = true;
12509  }
12510  Utilities->CallLogPop(135);
12511  return(true);
12512  }
12513  }
12514 // above dealt with immediate finds for leading point,
12515 // now deal with ordinary searches for leading point
12516  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
12517  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
12518  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
12519  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
12520  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
12521  SearchVector.clear();
12522  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
12523  {
12525  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12526  {
12527  FinishElement = true;
12528  }
12529  Utilities->CallLogPop(136);
12530  return(true);
12531  }
12532  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
12533  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12534  // note that CheckCount already increased to allow for XLinkPos & XLink
12535  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12536  SearchVector.clear();
12537  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12538  {
12540  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12541  {
12542  FinishElement = true;
12543  }
12544  Utilities->CallLogPop(137);
12545  return(true);
12546  }
12547 // here if failed to find match for leading point
12548  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12549  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12550  ShowMessage(
12551  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12552  Utilities->CallLogPop(138);
12553  return(false);
12554  }
12555 // leading point fully dealt with above
12556 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12557 // separately as covered in ordinary search.
12558 
12559  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12560  SearchVector.clear();
12561 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12562  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12563  {
12565  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12566  {
12567  FinishElement = true;
12568  }
12569  Utilities->CallLogPop(139);
12570  return(true);
12571  }
12572  ShowMessage(
12573  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12574  Utilities->CallLogPop(140);
12575  return(false); // failed to find required element
12576 }
12577 
12578 // ---------------------------------------------------------------------------
12579 
12580 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12581 /*
12582  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12583  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12584  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12585  Keep a count of entries in SearchVector during the current function call, so that this number can be
12586  erased for an unproductive branch search.
12587  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12588  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12589  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12590  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12591  If not any of above, store element in searchvector, set the new current element values from the
12592  SearchElement, then go back to the while loop for the next step in the search.
12593 */
12594 {
12595  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
12596  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
12597  int VectorCount = 0;
12598 
12599  while(true)
12600  {
12601  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
12602  {
12603  for(int x = 0; x < VectorCount; x++)
12604  {
12605  SearchVector.erase(SearchVector.end() - 1);
12606  }
12607  Utilities->CallLogPop(141);
12608  return(false);
12609  }
12610  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
12611  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
12612  TPrefDirElement SearchElement(NextTrackElement);
12613  SearchElement.TrackVectorPosition = NextPosition;
12614  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
12615  SearchElement.ELinkPos = NextELinkPos;
12616  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
12617  int NextXLinkPos;
12618  if(SearchElement.ELinkPos == 0)
12619  {
12620  NextXLinkPos = 1;
12621  }
12622  if(SearchElement.ELinkPos == 1)
12623  {
12624  NextXLinkPos = 0;
12625  }
12626  if(SearchElement.ELinkPos == 2)
12627  {
12628  NextXLinkPos = 3;
12629  }
12630  if(SearchElement.ELinkPos == 3)
12631  {
12632  NextXLinkPos = 2;
12633  }
12634  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
12635  {
12636  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
12637  // but may be buffers, continuation or gap
12638  SearchElement.XLinkPos = NextXLinkPos;
12639  }
12640 // can't set XLink or XLinkPos yet if the element is a leading point.
12641 // check if found it
12642  if(SearchElement.TrackVectorPosition == RequiredPosition)
12643  {
12644  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
12645  VectorCount++; // not really needed but include for tidyness
12646  TotalSearchCount++;
12647  Utilities->CallLogPop(142);
12648  return(true);
12649  }
12650 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
12651 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
12652 // at a time - drop this
12653 /*
12654  if(PrefDirVector.size() > 200)
12655  {
12656  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
12657  Utilities->CallLogPop(1419);
12658  return false;
12659  }
12660 */
12661 // check if a buffer or continuation
12662  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
12663  {
12664  for(int x = 0; x < VectorCount; x++)
12665  {
12666  SearchVector.erase(SearchVector.end() - 1);
12667  }
12668  Utilities->CallLogPop(143);
12669  return(false);
12670  }
12671 // check if reached an earlier position on search PrefDir with same entry value
12672  for(unsigned int x = 0; x < SearchVector.size(); x++)
12673  {
12674  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
12675  {
12676  for(int x = 0; x < VectorCount; x++)
12677  {
12678  SearchVector.erase(SearchVector.end() - 1);
12679  }
12680  Utilities->CallLogPop(144);
12681  return(false);
12682  }
12683  }
12684 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
12685 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
12686  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12687  {
12688  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
12689  {
12690  for(int x = 0; x < VectorCount; x++)
12691  {
12692  SearchVector.erase(SearchVector.end() - 1);
12693  }
12694  Utilities->CallLogPop(1417);
12695  return(false);
12696  }
12697  }
12698 
12699 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
12700 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
12701 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
12703  {
12704  for(int x = 0; x < VectorCount; x++)
12705  {
12706  SearchVector.erase(SearchVector.end() - 1);
12707  }
12708  Utilities->CallLogPop(1691);
12709  return(false);
12710  }
12711 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
12712  if(SearchVector.size() > 150)
12713  {
12714  for(int x = 0; x < VectorCount; x++)
12715  {
12716  SearchVector.erase(SearchVector.end() - 1);
12717  }
12718  Utilities->CallLogPop(1418);
12719  return(false);
12720  }
12721 // check if reached a leading point
12722  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
12723  {
12724 // push element with XLink set to position [1]
12725  SearchElement.XLink = SearchElement.Link[1];
12726  SearchElement.XLinkPos = 1;
12727  SearchVector.push_back(SearchElement);
12728  VectorCount++;
12729  TotalSearchCount++;
12730  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
12731  // Note that have to use a TTrackElement in the recursive search, so SearchElement
12732  // can't be used. NextTrackElement is the corresponding TTrackElement.
12733  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
12734  {
12735  Utilities->CallLogPop(145);
12736  return(true);
12737  }
12738  else
12739  {
12740 // remove leading point with XLinkPos [1]
12741  SearchVector.erase(SearchVector.end() - 1);
12742  VectorCount--;
12743 // push element with XLink set to position [3]
12744  SearchElement.XLink = SearchElement.Link[3];
12745  SearchElement.XLinkPos = 3;
12746  SearchVector.push_back(SearchElement);
12747  VectorCount++;
12748  TotalSearchCount++;
12749 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
12750  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
12751  {
12752  Utilities->CallLogPop(146);
12753  return(true);
12754  }
12755  else
12756  {
12757  for(int x = 0; x < VectorCount; x++)
12758  {
12759  SearchVector.erase(SearchVector.end() - 1);
12760  }
12761  Utilities->CallLogPop(147);
12762  return(false);
12763  }
12764  }
12765  } // if leading point
12766 
12767 // here if ordinary element, push it, inc vector & update CurrentTrackElement
12768 // ready for next element on PrefDir
12769  SearchVector.push_back(SearchElement);
12770  VectorCount++;
12771  TotalSearchCount++;
12772  XLinkPos = NextXLinkPos;
12773  CurrentTrackElement = SearchElement;
12774  } // while(true)
12775 }
12776 
12777 // ---------------------------------------------------------------------------
12778 
12780 /*
12781  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
12782  for each element on the search PrefDir, though if the last element is a leading point
12783  then the final XLink won't be set.
12784  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
12785  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
12786  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
12787 */
12788 {
12789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
12790  if(SearchVector.size() == 0)
12791  {
12792  throw Exception("Error, SearchVector empty");
12793  }
12794 // get first SearchElement in order to set last PrefDirelement
12795  TPrefDirElement SearchElement = SearchVector.at(0);
12796 
12797 // set last PrefDir element XLink & ELink values if not already set
12798 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
12799  for(int x = 0; x < 4; x++)
12800  {
12801  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
12802  {
12803  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
12804  {
12805  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
12806  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
12807  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
12808  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
12809  }
12810  int ELinkPos;
12811  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
12812  {
12813  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
12814  }
12815  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
12816  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
12817  {
12818  ELinkPos = 0;
12819  }
12820  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
12821  {
12822  ELinkPos = 3;
12823  }
12824  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
12825  {
12826  ELinkPos = 2;
12827  }
12828  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
12829  {
12830  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
12831  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
12832  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
12833  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
12834  }
12835  break; // no point going any further
12836  }
12837  }
12838 // set EXNumber for last PrefDir element, unless already set
12839 // won't be set if was first element or a leading point
12840  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
12841  {
12842 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
12843  int EXArray[32][2] = {
12844  {4,6},{2,8}, //horizontal & vertical
12845  {2,4},{6,2},{8,6},{4,8}, //sharp curves
12846  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
12847  {1,9},{3,7} //forward & reverse diagonals
12848 */
12849 
12850  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
12851  {
12852  throw Exception("Error in EntryExitNumber 1");
12853  }
12854  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
12855  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
12856  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
12857  }
12858 // Last PrefDir element now complete
12859 
12860 // construct remaining PrefDir elements from searchvector
12861  for(unsigned int x = 0; x < SearchVector.size(); x++)
12862  {
12863  SearchElement = SearchVector.at(x);
12864  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
12865  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
12866  PrefDirElement.ELink = SearchElement.ELink;
12867  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
12868  PrefDirElement.XLink = SearchElement.XLink;
12869  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
12870 // if XLink & XLinkPos not set don't account for them in CheckCount
12871  if(PrefDirElement.XLink == -1)
12872  {
12873  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12874  }
12875  // & TrackVectorPosition
12876  else
12877  {
12878  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
12879  }
12880  // XLink, XLinkPos, TrackVectorPosition
12881 
12882 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
12883  if(PrefDirElement.XLink != -1)
12884  {
12885  if(!(PrefDirElement.EntryExitNumber()))
12886  {
12887  throw Exception("Error in EntryExitNumber 2");
12888  }
12889  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
12890  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
12891  PrefDirElement.CheckCount++;
12892  // all values now incorporated if not a leading point
12893  }
12894 // store PrefDir element
12895  StorePrefDirElement(2, PrefDirElement);
12896  }
12897 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
12898  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
12899  {
12900  if(ValidatePrefDir(2))
12901  {
12902  ;
12903  } // error messages given within function
12904 
12905  }
12907 /* drop this, check dropped from search
12908  if(PrefDirVector.size() > 200)
12909  {
12910  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
12911  }
12912 */
12913  Utilities->CallLogPop(148);
12914 }
12915 
12916 // ---------------------------------------------------------------------------
12917 
12918 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12919 /*
12920  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12921  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12922 */
12923 {
12924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12925  LeadingPoints = false;
12926  if(PrefDirVector.empty())
12927  {
12928  Utilities->CallLogPop(1786);
12929  return(false); // should never be empty but allow for it for safety
12930  }
12931  if(PrefDirVector.size() == 1)
12932  {
12933  Utilities->CallLogPop(149);
12934  return(false); // can't end if only one element
12935  }
12936 /*
12937  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12938  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12939  {
12940  Utilities->CallLogPop(150);
12941  return true;
12942  }
12943 */
12944 // allow for anything but leading points
12945  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12946  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12947  {
12948  Utilities->CallLogPop(1776);
12949  return(true);
12950  }
12951  else
12952  {
12953  LeadingPoints = true;
12954  Utilities->CallLogPop(151);
12955  return(false);
12956  }
12957 }
12958 
12959 // ---------------------------------------------------------------------------
12960 
12962 /*
12963  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12964  and that every element is connected to the next element
12965 */
12966 {
12967  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12968  int Position;
12969  AnsiString ErrorString;
12970  bool Error = false;
12971 
12972  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12973  {
12974  if(PrefDirVector.at(x).HLoc == -2000000000)
12975  {
12976  Error = true;
12977  ErrorString = "HLoc";
12978  Position = x;
12979  }
12980  if(PrefDirVector.at(x).VLoc == -2000000000)
12981  {
12982  Error = true;
12983  ErrorString = "VLoc";
12984  Position = x;
12985  }
12986  if(PrefDirVector.at(x).ELink == -1)
12987  {
12988  Error = true;
12989  ErrorString = "ELink";
12990  Position = x;
12991  }
12992  if(PrefDirVector.at(x).ELinkPos == -1)
12993  {
12994  Error = true;
12995  ErrorString = "ELinkPos";
12996  Position = x;
12997  }
12998  if(PrefDirVector.at(x).XLink == -1)
12999  {
13000  Error = true;
13001  ErrorString = "XLink";
13002  Position = x;
13003  }
13004  if(PrefDirVector.at(x).XLinkPos == -1)
13005  {
13006  Error = true;
13007  ErrorString = "XLinkPos";
13008  Position = x;
13009  }
13010  if(PrefDirVector.at(x).SpeedTag == 0)
13011  {
13012  Error = true;
13013  ErrorString = "Tag";
13014  Position = x;
13015  }
13016  if(PrefDirVector.at(x).TrackVectorPosition == -1)
13017  {
13018  Error = true;
13019  ErrorString = "TrackVectorPosition";
13020  Position = x;
13021  }
13022  if(PrefDirVector.at(x).EXNumber == -1)
13023  {
13024  Error = true;
13025  ErrorString = "EXNumber";
13026  Position = x;
13027  }
13028  if(PrefDirVector.at(x).CheckCount != 9)
13029  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
13030  {
13031  Error = true;
13032  ErrorString = "CheckCount";
13033  Position = x;
13034  }
13035 // extra checks
13036  if(PrefDirVector.at(x).EXGraphicPtr == 0)
13037  {
13038  Error = true;
13039  ErrorString = "EntryGraphicPtr";
13040  Position = x;
13041  }
13042  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
13043  {
13044  Error = true;
13045  ErrorString = "EntryDirectionGraphicPtr";
13046  Position = x;
13047  }
13048 // end of extra checks
13049  if(x > 0)
13050  {
13051  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
13052  {
13053  Error = true;
13054  ErrorString = "Last XLink not connected to this element";
13055  Position = x;
13056  }
13057  }
13058  }
13059  if(Error)
13060  {
13061  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
13062  }
13063  else
13064  {
13065  Utilities->CallLogPop(153);
13066  return(true);
13067  }
13068 }
13069 
13070 // ---------------------------------------------------------------------------
13071 
13072 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
13073 /*
13074  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
13075  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
13076  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
13077  or a leading point.
13078 */
13079 {
13080  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13081  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
13082  {
13083  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
13084  {
13085  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
13086  {
13087  ErasePrefDirElementAt(1, PrefDirVecPos);
13088  }
13089  if(PrefDirVector.size() == 0)
13090  {
13091  Utilities->CallLogPop(154);
13092  return(true);
13093  }
13094  if(PrefDirVector.size() == 1)
13095  {
13096  PrefDirVector.at(x - 1).ELinkPos = -1;
13097  PrefDirVector.at(x - 1).ELink = -1;
13098  PrefDirVector.at(x - 1).XLinkPos = -1;
13099  PrefDirVector.at(x - 1).XLink = -1;
13100  PrefDirVector.at(x - 1).EXNumber = -1;
13101  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13102  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13103  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
13104  Utilities->CallLogPop(155);
13105  return(true);
13106  }
13107  // here with truncate element not first element, so ELink & ELinkPos set
13108  // unset XLink & Pos if a leading point
13109  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
13110  {
13111  PrefDirVector.at(x - 1).XLinkPos = -1;
13112  PrefDirVector.at(x - 1).XLink = -1;
13113  PrefDirVector.at(x - 1).EXNumber = -1;
13114  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13115  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13116  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
13117  Utilities->CallLogPop(156);
13118  return(true);
13119  }
13120  Utilities->CallLogPop(157);
13121  return(true);
13122  }
13123  }
13124  Utilities->CallLogPop(158);
13125  return(false);
13126 }
13127 
13128 // ---------------------------------------------------------------------------
13129 
13130 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
13131 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
13132 /*
13133  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
13134  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
13135  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
13136  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
13137  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
13138  displayed.
13139 */
13140 {
13141  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
13142  AnsiString((short)BuildingPrefDir));
13143  int HPos, VPos;
13144 
13145  if(PrefDirSize() == 0)
13146  {
13147  Utilities->CallLogPop(159);
13148  return;
13149  }
13150  for(unsigned int x = 0; x < PrefDirSize(); x++)
13151  {
13152  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13153 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
13154 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
13155 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
13156  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
13157  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
13158  // only the front half of which will be overplotted by the back of the train, then when the train is
13159  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
13160  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13161  {
13162  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
13163  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
13164  {
13165  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13166  }
13167  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
13168  // Route, no direction if a single element
13169  {
13170  if(x == 0)
13171  {
13172  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13173  }
13174  if(x == (PrefDirSize() - 1))
13175  {
13176  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13177  }
13178  }
13179  }
13180  }
13181 
13182 // set start & end element colours if building a PrefDir
13183  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
13184  {
13185  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
13186  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
13187  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
13188  // set last element colour
13189  if(PrefDirSize() > 1)
13190  {
13191  unsigned int LatestPos = PrefDirSize() - 1;
13192  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
13193  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
13194  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
13195  }
13196  }
13197  Disp->Update();
13198  Utilities->CallLogPop(160);
13199 }
13200 
13201 // ---------------------------------------------------------------------------
13202 
13204 /*
13205  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
13206  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
13207 */
13208 {
13209  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
13210  if(PrefDirSize() == 0)
13211  {
13212  Utilities->CallLogPop(1547);
13213  return;
13214  }
13215  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13216  bool FoundFlag;
13218  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13219 
13220  while(MMIT != PrefDir4MultiMap.end())
13221  {
13222  H = MMIT->first.first;
13223  V = MMIT->first.second;
13224  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13225  // always found in order, any missing have PrefDirPosx == -1
13226  if(PrefDirPos0 > -1)
13227  {
13228  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13229  }
13230  if(PrefDirPos1 > -1)
13231  {
13232  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
13233  }
13234  if(PrefDirPos2 > -1)
13235  {
13236  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
13237  }
13238  if(PrefDirPos3 > -1)
13239  {
13240  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
13241  }
13242  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13243  {
13244  // need to plot all 4 in order to obtain all the direction graphics
13245  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13246  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13247  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13248  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13249  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13250  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13251  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13252  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13253  MMIT++;
13254  MMIT++;
13255  MMIT++;
13256  MMIT++;
13257  }
13258  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13259  {
13260  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13261  {
13262  // 0 & 1 constitute the bidirectional PrefDir
13263  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13264  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13265  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13266  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13267  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13268  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13269  MMIT++;
13270  MMIT++;
13271  MMIT++;
13272  }
13273  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13274  {
13275  // 0 & 2 constitute the bidirectional PrefDir
13276  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13277  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13278  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13279  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13280  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13281  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13282  MMIT++;
13283  MMIT++;
13284  MMIT++;
13285  }
13286  else
13287  {
13288  // 1 & 2 constitute the bidirectional PrefDir
13289  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13290  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13291  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13292  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13293  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13294  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13295  MMIT++;
13296  MMIT++;
13297  MMIT++;
13298  }
13299  }
13300  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13301  {
13302  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13303  {
13304  // 0 & 1 constitute the bidirectional PrefDir
13305  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13306  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13307  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13308  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13309  MMIT++;
13310  MMIT++;
13311  }
13312  else
13313  {
13314  // 2 unidirectional PrefDirs
13315  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13316  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13317  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13318  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13319  MMIT++;
13320  MMIT++;
13321  }
13322  }
13323  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13324  {
13325  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13326  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13327  MMIT++;
13328  }
13329  }
13330  Disp->Update();
13331  Utilities->CallLogPop(1548);
13332 }
13333 
13334 // ---------------------------------------------------------------------------
13335 
13336 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
13337 {
13338  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
13339  int TempInt;
13340 
13341  ClearPrefDir();
13342  int NumberOfPrefDirElements = 0;
13343 
13344  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13345  for(int x = 0; x < NumberOfPrefDirElements; x++)
13346  {
13347  VecFile >> TempInt; // TrackVectorPosition
13348  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
13349  LoadPrefDirElement.TrackVectorPosition = TempInt;
13350  VecFile >> TempInt;
13351  LoadPrefDirElement.ELink = TempInt;
13352  VecFile >> TempInt;
13353  LoadPrefDirElement.ELinkPos = TempInt;
13354  VecFile >> TempInt;
13355  LoadPrefDirElement.XLink = TempInt;
13356  VecFile >> TempInt;
13357  LoadPrefDirElement.XLinkPos = TempInt;
13358  VecFile >> TempInt;
13359  LoadPrefDirElement.EXNumber = TempInt;
13360  VecFile >> TempInt;
13361  LoadPrefDirElement.CheckCount = TempInt;
13362  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13363  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13364  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13365  if(!(LoadPrefDirElement.IsARoute))
13366  {
13367  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13368  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13369  }
13370  else
13371  {
13372  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13373  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13374  LoadPrefDirElement.PrefDirRoute);
13375  }
13376  StorePrefDirElement(5, LoadPrefDirElement);
13377  Utilities->LoadFileString(VecFile); // marker
13378  }
13380  Utilities->CallLogPop(161);
13381 }
13382 
13383 // ---------------------------------------------------------------------------
13384 
13385 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
13386 {
13387  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
13388  int TempInt;
13389 
13390  ClearPrefDir();
13391  int NumberOfPrefDirElements = 0;
13392 
13393  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13394  for(int x = 0; x < NumberOfPrefDirElements; x++)
13395  {
13396  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
13397  VecFile >> TempInt; // TrackVectorPosition
13398  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
13399  LoadPrefDirElement.TrackVectorPosition = TempInt;
13400  VecFile >> TempInt;
13401  LoadPrefDirElement.ELink = TempInt;
13402  VecFile >> TempInt;
13403  LoadPrefDirElement.ELinkPos = TempInt;
13404  VecFile >> TempInt;
13405  LoadPrefDirElement.XLink = TempInt;
13406  VecFile >> TempInt;
13407  LoadPrefDirElement.XLinkPos = TempInt;
13408  VecFile >> TempInt;
13409  LoadPrefDirElement.EXNumber = TempInt;
13410  VecFile >> TempInt;
13411  LoadPrefDirElement.CheckCount = TempInt;
13412  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13413  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13414  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13415  if(!(LoadPrefDirElement.IsARoute))
13416  {
13417  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13418  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13419  }
13420  else
13421  {
13422  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13423  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13424  LoadPrefDirElement.PrefDirRoute);
13425  }
13426  StorePrefDirElement(0, LoadPrefDirElement);
13427  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
13428  }
13430  Utilities->CallLogPop(1509);
13431 }
13432 
13433 // ---------------------------------------------------------------------------
13434 
13435 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
13436 /*
13437  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
13438  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
13439 */
13440 {
13441  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
13442  int TempInt;
13443  int NumberOfPrefDirElements = 0;
13444 
13445  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13446  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
13447  {
13448  Utilities->CallLogPop(1152);
13449  return(false);
13450  }
13451  for(int x = 0; x < NumberOfPrefDirElements; x++)
13452  {
13453  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
13454  {
13455  Utilities->CallLogPop(1766);
13456  return(false);
13457  }
13458  VecFile >> TempInt;
13459  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
13460  {
13461  Utilities->CallLogPop(163);
13462  return(false);
13463  }
13464  VecFile >> TempInt;
13465  if((TempInt < -1) || (TempInt > 9)) // ELink
13466  {
13467  Utilities->CallLogPop(162);
13468  return(false);
13469  }
13470  VecFile >> TempInt;
13471  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
13472  {
13473  Utilities->CallLogPop(164);
13474  return(false);
13475  }
13476  VecFile >> TempInt;
13477  if((TempInt < -1) || (TempInt > 9)) // XLink
13478  {
13479  Utilities->CallLogPop(165);
13480  return(false);
13481  }
13482  VecFile >> TempInt;
13483  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
13484  {
13485  Utilities->CallLogPop(166);
13486  return(false);
13487  }
13488  VecFile >> TempInt;
13489  if((TempInt < -1) || (TempInt > 27)) // EXNumber
13490  {
13491  Utilities->CallLogPop(167);
13492  return(false);
13493  }
13494  VecFile >> TempInt;
13495  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
13496  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
13497  // ELinkPos, XLink, XLinkPos & EXNumber
13498  {
13499  Utilities->CallLogPop(168);
13500  return(false);
13501  }
13502  VecFile >> TempInt;
13503  if((TempInt != 0) && (TempInt != 1)) // RouteElement
13504  {
13505  Utilities->CallLogPop(1147);
13506  return(false);
13507  }
13508  VecFile >> TempInt;
13509  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
13510  {
13511  Utilities->CallLogPop(1510);
13512  return(false);
13513  }
13514  VecFile >> TempInt;
13515  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
13516  {
13517  Utilities->CallLogPop(1148);
13518  return(false);
13519  }
13520  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
13521  {
13522  Utilities->CallLogPop(1700);
13523  return(false);
13524  }
13525  }
13526  Utilities->CallLogPop(169);
13527  return(true);
13528 }
13529 
13530 // ---------------------------------------------------------------------------
13531 
13532 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
13533 {
13534  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13535  int NumberOfPrefDirElements = PrefDirVector.size();
13536 
13537  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13538  for(int y = 0; y < NumberOfPrefDirElements; y++)
13539  {
13540  VecFile << y << '\n'; // extra
13541  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13542  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13543  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13544  VecFile << PrefDirVector.at(y).XLink << '\n';
13545  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13546  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13547  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13548  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13549  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13550  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13551  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13552  {
13553  VecFile << "************" << '\0' << '\n'; // marker
13554  }
13555  else
13556  {
13557  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13558  }
13559  }
13560  Utilities->CallLogPop(170);
13561 }
13562 
13563 // ---------------------------------------------------------------------------
13564 
13565 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13566 {
13567  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13568  int NumberOfSearchElements = SearchVector.size();
13569 
13570  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13571  for(int y = 0; y < NumberOfSearchElements; y++)
13572  {
13573  VecFile << y << '\n'; // extra
13574  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13575  VecFile << SearchVector.at(y).ELink << '\n';
13576  VecFile << SearchVector.at(y).ELinkPos << '\n';
13577  VecFile << SearchVector.at(y).XLink << '\n';
13578  VecFile << SearchVector.at(y).XLinkPos << '\n';
13579  VecFile << SearchVector.at(y).EXNumber << '\n';
13580  VecFile << SearchVector.at(y).CheckCount << '\n';
13581  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13582  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13583  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13584  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13585  {
13586  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13587  }
13588  else
13589  {
13590  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13591  }
13592  }
13593  Utilities->CallLogPop(1847);
13594 }
13595 
13596 // ---------------------------------------------------------------------------
13597 
13598 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
13599 /*
13600  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
13601  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
13602 */
13603 {
13604  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
13605  AnsiString(VLoc));
13606  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
13607 
13608  if(VecPos > -1)
13609  {
13610  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
13611  }
13612  else
13613  {
13614  Utilities->CallLogPop(171);
13615  return;
13616  }
13617  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
13618  if(VecPos > -1)
13619  {
13620  ErasePrefDirElementAt(3, VecPos);
13621  }
13622  else
13623  {
13624  Utilities->CallLogPop(172);
13625  return;
13626  }
13627  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
13628  if(VecPos > -1)
13629  {
13630  ErasePrefDirElementAt(4, VecPos);
13631  }
13632  else
13633  {
13634  Utilities->CallLogPop(173);
13635  return;
13636  }
13637  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
13638  if(VecPos > -1)
13639  {
13640  ErasePrefDirElementAt(5, VecPos);
13641  }
13642  else
13643  {
13644  Utilities->CallLogPop(174);
13645  return;
13646  }
13647  Utilities->CallLogPop(175);
13648 }
13649 
13650 // ---------------------------------------------------------------------------
13651 /*
13652  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
13653  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
13654 
13655  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
13656  in their place so that existing linkages will be preserved. At this stage this function is called to remove
13657  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
13658  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
13659  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
13660  PrefDirVector to correspond to the new track layout.
13661 
13662  {
13663  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
13664  if(PrefDirSize() == 0)
13665  {
13666  Utilities->CallLogPop(176);
13667  return;
13668  }
13669  for(int x=(PrefDirVector.size()-1);x>=0;x--)
13670  {
13671  int TV = PrefDirVector.at(x).TrackVectorPosition;
13672  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
13673  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
13674  if(Track->BlankElementAt(0, TV))
13675  {
13676  ErasePrefDirElementAt(6, x);
13677  }
13678  //if was a blankelement at x then ConnELink and ConnXLink both -1
13679  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
13680  {
13681  ErasePrefDirElementAt(7, x);
13682  }
13683  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
13684  //needs to be erased once, but if don't use 'else' then will erase two elements
13685  //since 'x' will correspond to the element after the first erased element
13686  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
13687  {
13688  ErasePrefDirElementAt(8, x);
13689  }
13690  }
13691  Utilities->CallLogPop(177);
13692  }
13693 */
13694 // ---------------------------------------------------------------------------
13695 
13696 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
13697 /*
13698  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
13699  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
13700 */
13701 {
13702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
13703  bool AlreadyPresent, FoundFlag;
13704  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13705 
13706  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
13707  {
13708  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
13709  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13710  AlreadyPresent = false;
13711  if(FoundFlag)
13712  {
13713  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
13714  {
13715  AlreadyPresent = true;
13716  }
13717  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
13718  {
13719  AlreadyPresent = true;
13720  }
13721  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
13722  {
13723  AlreadyPresent = true;
13724  }
13725  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
13726  {
13727  AlreadyPresent = true;
13728  }
13729  }
13730  if(!AlreadyPresent)
13731  {
13732  StorePrefDirElement(4, TempElement);
13733  }
13734  }
13736  Utilities->CallLogPop(178);
13737 }
13738 /* earlier brute force search
13739  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
13740  {
13741  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
13742  bool AlreadyPresent = false;
13743  for(unsigned int y = 0;y<PrefDirSize();y++)
13744  {
13745  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
13746  }
13747  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
13748  }
13749 */
13750 
13751 // ---------------------------------------------------------------------------
13752 
13754 /*
13755  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
13756  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
13757  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
13758  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
13759  positions are likely to have changed, so this function is called to reset all the necessary connections and
13760  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
13761  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
13762  shouldn't have changed.
13763 */
13764 {
13765  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
13766  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13767  {
13768  bool FoundFlag;
13769  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13770  if(FoundFlag)
13771  {
13772  PrefDirVector.at(x).TrackVectorPosition = VecPos;
13773  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
13774  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
13775  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
13776  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
13777  for(unsigned int z = 0; z < 4; z++)
13778  {
13779  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
13780  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
13781  }
13782  }
13783  else
13784  {
13785  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
13786  }
13787  }
13788  Utilities->CallLogPop(179);
13789 }
13790 
13791 // ---------------------------------------------------------------------------
13792 
13794 /*
13795  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
13796 */
13797 {
13798  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
13799  bool DiscrepancyFound = false;
13800 
13801  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13802  {
13803  bool FoundFlag;
13804  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13805  if(FoundFlag)
13806  {
13807  TPrefDirElement PE = PrefDirVector.at(x);
13808  if(PE.TrackVectorPosition != VecPos)
13809  {
13810  DiscrepancyFound = true;
13811  break;
13812  }
13813  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13814  {
13815  DiscrepancyFound = true;
13816  break;
13817  }
13818  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13819  {
13820  DiscrepancyFound = true;
13821  break;
13822  }
13823  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
13824  {
13825  DiscrepancyFound = true;
13826  break;
13827  }
13828  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
13829  {
13830  DiscrepancyFound = true;
13831  break;
13832  }
13833  }
13834  else
13835  {
13836  DiscrepancyFound = true;
13837  }
13838  }
13839  if(DiscrepancyFound)
13840  {
13841  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
13842  ClearPrefDir(); // also clears multimap
13843  }
13844  Utilities->CallLogPop(1436);
13845 }
13846 
13847 // ---------------------------------------------------------------------------
13848 
13850 /*
13851  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
13852  return true for OK
13853 */
13854 {
13855  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
13856  bool DiscrepancyFound = false;
13857 
13858  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13859  {
13860  bool FoundFlag;
13861  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
13862  if(FoundFlag)
13863  {
13864  TPrefDirElement PE = PrefDirVector.at(x);
13865  if(PE.TrackVectorPosition != VecPos)
13866  {
13867  DiscrepancyFound = true;
13868  }
13869  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
13870  {
13871  DiscrepancyFound = true;
13872  break;
13873  }
13874  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
13875  {
13876  DiscrepancyFound = true;
13877  break;
13878  }
13879  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
13880  {
13881  DiscrepancyFound = true;
13882  break;
13883  }
13884  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
13885  {
13886  DiscrepancyFound = true;
13887  break;
13888  }
13889  }
13890  else
13891  {
13892  DiscrepancyFound = true;
13893  }
13894  }
13895  Utilities->CallLogPop(1512);
13896  return(!DiscrepancyFound);
13897 }
13898 
13899 // ---------------------------------------------------------------------------
13900 
13901 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
13902 /*
13903  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
13904  turn and for the overall sizes.
13905 */
13906 {
13907  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
13908  bool FoundFlag = false;
13909  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
13910 
13911  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
13912  {
13913  TPrefDirElement CheckElement = PrefDirVector.at(a);
13914  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13915  if(!FoundFlag)
13916  {
13917  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13918  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13919  }
13920  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13921  {
13922  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13923  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13924  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13925  }
13926  }
13927  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13928  {
13929  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13930  + " Caller=" + (AnsiString)Caller);
13931  }
13932  Utilities->CallLogPop(180);
13933 }
13934 
13935 // ---------------------------------------------------------------------------
13936 
13937 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13938  int &PrefDirPos3)
13939 /*
13940  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13941  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
13942  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13943  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13944  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13945 */
13946 {
13947  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13948  AnsiString(VLoc));
13949  THVPair PrefDirMapKeyPair;
13950 
13951  PrefDirPos0 = -1;
13952  PrefDirPos1 = -1;
13953  PrefDirPos2 = -1;
13954  PrefDirPos3 = -1;
13955  FoundFlag = false;
13956  PrefDirMapKeyPair.first = HLoc;
13957  PrefDirMapKeyPair.second = VLoc;
13958  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13959 
13960  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13961  if(ItPair.first == ItPair.second) //none found
13962  {
13963  Utilities->CallLogPop(181);
13964  return;
13965  }
13966  else
13967  {
13968  FoundFlag = true;
13969  PrefDirPos0 = ItPair.first->second;
13970  ItPair.first++;
13971  if(ItPair.first == ItPair.second)
13972  {
13973  Utilities->CallLogPop(182); //only one found
13974  return;
13975  }
13976  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13977  {
13978  PrefDirPos1 = ItPair.first->second;
13979  }
13980  ItPair.first++;
13981  if(ItPair.first == ItPair.second)
13982  {
13983  Utilities->CallLogPop(183); //2 found
13984  return;
13985  }
13986  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13987  {
13988  PrefDirPos2 = ItPair.first->second;
13989  }
13990  ItPair.first++;
13991  if(ItPair.first == ItPair.second)
13992  {
13993  Utilities->CallLogPop(184); //3 found
13994  return;
13995  }
13996  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13997  {
13998  PrefDirPos3 = ItPair.first->second; //4 found
13999  }
14000  }
14001  Utilities->CallLogPop(185);
14002 }
14003 
14004 // ---------------------------------------------------------------------------
14005 
14006 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14007 { //not used after modified the pref dir checking function at v2.13.0
14008  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
14009  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14010  try
14011  {
14012  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
14013  + "," + AnsiString(LinkNumberPos));
14014  bool FoundFlag;
14015  int PD0, PD1, PD2, PD3;
14016  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14017  {
14018  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14019  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14020  PD0, PD1, PD2, PD3);
14021  if(!FoundFlag)
14022  {
14023  Utilities->CallLogPop(2282);
14024  return(false);
14025  }
14026  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14027  {
14028  if(PD0 > -1)
14029  {
14030  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
14031  {
14032  LinkedPrefDirVectorNumber = PD0;
14033  Utilities->CallLogPop(2283);
14034  return(true);
14035  }
14036  }
14037  if(PD1 > -1)
14038  {
14039  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
14040  {
14041  LinkedPrefDirVectorNumber = PD1;
14042  Utilities->CallLogPop(2284);
14043  return(true);
14044  }
14045  }
14046  }
14047  if(PD0 > -1)
14048  {
14049  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
14050  {
14051  LinkedPrefDirVectorNumber = PD0;
14052  Utilities->CallLogPop(2285);
14053  return(true);
14054  }
14055  }
14056  if(PD1 > -1)
14057  {
14058  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
14059  {
14060  LinkedPrefDirVectorNumber = PD1;
14061  Utilities->CallLogPop(2286);
14062  return(true);
14063  }
14064  }
14065  if(PD2 > -1)
14066  {
14067  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
14068  {
14069  LinkedPrefDirVectorNumber = PD2;
14070  Utilities->CallLogPop(2287);
14071  return(true);
14072  }
14073  }
14074  if(PD3 > -1)
14075  {
14076  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
14077  {
14078  LinkedPrefDirVectorNumber = PD3;
14079  Utilities->CallLogPop(2288);
14080  return(true);
14081  }
14082  }
14083  LinkedPrefDirVectorNumber = -1;
14084  Utilities->CallLogPop(2289);
14085  return(false);
14086  }
14087  else //buffer or continuation, no link at position 0 but not a failure
14088  {
14089  LinkedPrefDirVectorNumber = -1;
14090  Utilities->CallLogPop(2290);
14091  return(true);
14092  }
14093  }
14094  catch(const Exception &e) //non error catch
14095  {
14096  LinkedPrefDirVectorNumber = -1;
14097  Utilities->CallLogPop(2291);
14098  return(false);
14099  }
14100 }
14101 
14102 // ---------------------------------------------------------------------------
14103 
14104 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14105 { //not used after modified the pref dir checking function at v2.13.0
14106  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
14107  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14108  try
14109  {
14110  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
14111  + "," + AnsiString(LinkNumberPos));
14112  bool FoundFlag;
14113  int PD0, PD1, PD2, PD3;
14114  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14115  {
14116  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14117  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14118  PD0, PD1, PD2, PD3);
14119  if(!FoundFlag)
14120  {
14121  Utilities->CallLogPop(2468);
14122  return(false);
14123  }
14124  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14125  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
14126  if(PD0 > -1)
14127  {
14128  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
14129  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
14130  {
14131  LinkedPrefDirVectorNumber = PD0;
14132  Utilities->CallLogPop(2469);
14133  return(true);
14134  }
14135  }
14136  if(PD1 > -1)
14137  {
14138  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
14139  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
14140  {
14141  LinkedPrefDirVectorNumber = PD1;
14142  Utilities->CallLogPop(2470);
14143  return(true);
14144  }
14145  }
14146  LinkedPrefDirVectorNumber = -1;
14147  Utilities->CallLogPop(2471);
14148  return(false);
14149  }
14150  if(PD0 > -1)
14151  {
14152  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14153  {
14154  LinkedPrefDirVectorNumber = PD0;
14155  Utilities->CallLogPop(2472);
14156  return(true);
14157  }
14158  }
14159  if(PD1 > -1)
14160  {
14161  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14162  {
14163  LinkedPrefDirVectorNumber = PD1;
14164  Utilities->CallLogPop(2473);
14165  return(true);
14166  }
14167  }
14168  if(PD2 > -1)
14169  {
14170  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14171  {
14172  LinkedPrefDirVectorNumber = PD2;
14173  Utilities->CallLogPop(2474);
14174  return(true);
14175  }
14176  }
14177  if(PD3 > -1)
14178  {
14179  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14180  {
14181  LinkedPrefDirVectorNumber = PD3;
14182  Utilities->CallLogPop(2475);
14183  return(true);
14184  }
14185  }
14186  LinkedPrefDirVectorNumber = -1;
14187  Utilities->CallLogPop(2476);
14188  return(false);
14189  }
14190  else //buffer or continuation, no link at position 0 but not a failure
14191  {
14192  LinkedPrefDirVectorNumber = -1;
14193  Utilities->CallLogPop(2477);
14194  return(true);
14195  }
14196  }
14197  catch(const Exception &e) //non error catch
14198  {
14199  LinkedPrefDirVectorNumber = -1;
14200  Utilities->CallLogPop(2478);
14201  return(false);
14202  }
14203 }
14204 
14205 // ---------------------------------------------------------------------------
14206 
14208 {
14209  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
14210  bool FoundFlag; //not used
14211  int PD0, PD1, PD2, PD3;
14212  //recover all PDs at the H & V of PDPtr
14213  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
14214 
14215  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
14216  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
14217 
14218  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
14219  {
14220  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
14221  {
14222  Utilities->CallLogPop(2292);
14223  return(true);
14224  }
14225  }
14226  if(PD1 > -1)
14227  {
14228  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
14229  {
14230  Utilities->CallLogPop(2293);
14231  return(true);
14232  }
14233  }
14234  if(PD2 > -1)
14235  {
14236  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
14237  {
14238  Utilities->CallLogPop(2294);
14239  return(true);
14240  }
14241  }
14242  if(PD3 > -1)
14243  {
14244  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
14245  {
14246  Utilities->CallLogPop(2295);
14247  return(true);
14248  }
14249  }
14250  Utilities->CallLogPop(2296);
14251  return(false);
14252 }
14253 
14254 // ---------------------------------------------------------------------------
14255 
14256 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
14257 /*
14258  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
14259 */
14260 {
14261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
14262  PrefDirVector.push_back(LoadPrefDirElement);
14263  THVPair PrefDir4MultiMapKeyPair;
14264  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
14265 
14266  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
14267  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
14268  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
14269  PrefDir4MultiMapEntry.second = LastElementNumber(68);
14270  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
14271 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
14272  Utilities->CallLogPop(186);
14273 }
14274 
14275 // ---------------------------------------------------------------------------
14276 
14277 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
14278 /*
14279  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
14280  4MultiMap if they are greater than the erased value.
14281 */
14282 {
14283  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
14284  bool FoundFlag;
14285 
14286  if(!PrefDirVector.empty())
14287  {
14288  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
14289  if(!FoundFlag)
14290  {
14291  throw Exception("Failed to find PrefDir4MultiMap erase element");
14292  }
14293  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
14294  PrefDir4MultiMap.erase(EraseIt);
14295  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
14297  }
14298  Utilities->CallLogPop(187);
14299 }
14300 
14301 // ---------------------------------------------------------------------------
14302 
14303 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
14304 /*
14305  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
14306  4MultiMap if they are greater than the erased value.
14307 */
14308 {
14309  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
14310  AnsiString(ErasedElementNumber));
14311  if(!PrefDir4MultiMap.empty())
14312  {
14313  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
14314  {
14315  if(MapPtr->second > ErasedElementNumber)
14316  {
14317  MapPtr->second--;
14318  }
14319  }
14320  }
14321  Utilities->CallLogPop(1450);
14322 }
14323 
14324 // ---------------------------------------------------------------------------
14325 
14326 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
14327 /*
14328  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
14329  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
14330  nothing is found this is an error but the error message is given in the calling function.
14331 */
14332 {
14333  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
14334  FoundFlag = false;
14335  if(PrefDirVectorPosition >= PrefDirVector.size())
14336  {
14337  throw Exception("PrefDirVectorPosition out of range");
14338  }
14339  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
14340  THVPair PrefDir4MultiMapKeyPair;
14341 
14342  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
14343  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
14344  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14345 
14346  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14347  if(ItPair.first == ItPair.second)
14348  {
14349  Utilities->CallLogPop(188);
14350  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
14351  }
14352  else
14353  {
14354  if(ItPair.first->second == PrefDirVectorPosition)
14355  {
14356  FoundFlag = true;
14357  Utilities->CallLogPop(189);
14358  return(ItPair.first);
14359  }
14360  ItPair.first++;
14361  if(ItPair.first == ItPair.second)
14362  {
14363  Utilities->CallLogPop(190);
14364  return(ItPair.first); // nothing found
14365  }
14366  if(ItPair.first->second == PrefDirVectorPosition)
14367  {
14368  FoundFlag = true;
14369  Utilities->CallLogPop(191);
14370  return(ItPair.first);
14371  }
14372  ItPair.first++;
14373  if(ItPair.first == ItPair.second)
14374  {
14375  Utilities->CallLogPop(192);
14376  return(ItPair.first); // nothing found
14377  }
14378  if(ItPair.first->second == PrefDirVectorPosition)
14379  {
14380  FoundFlag = true;
14381  Utilities->CallLogPop(193);
14382  return(ItPair.first);
14383  }
14384  ItPair.first++;
14385  if(ItPair.first == ItPair.second)
14386  {
14387  Utilities->CallLogPop(194);
14388  return(ItPair.first); // nothing found
14389  }
14390  if(ItPair.first->second == PrefDirVectorPosition)
14391  {
14392  FoundFlag = true;
14393  Utilities->CallLogPop(195);
14394  return(ItPair.first);
14395  }
14396  }
14397  Utilities->CallLogPop(196);
14398  return(ItPair.first); // nothing found
14399 }
14400 
14401 // ---------------------------------------------------------------------------
14402 
14403 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
14404 /*
14405  Although there may be up to four entries at one H & V position this function gets just one. It is
14406  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
14407  at H & V.
14408 */
14409 {
14410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
14411  THVPair PrefDir4MultiMapKeyPair;
14412 
14413  PrefDir4MultiMapKeyPair.first = HLoc;
14414  PrefDir4MultiMapKeyPair.second = VLoc;
14415  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14416 
14417  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14418  if(ItPair.first == ItPair.second) // nothing found
14419  {
14420  Utilities->CallLogPop(197);
14421  return(-1);
14422  }
14423  else
14424  {
14425  Utilities->CallLogPop(198);
14426  return(ItPair.first->second);
14427  }
14428 }
14429 
14430 // ---------------------------------------------------------------------------
14431 
14432 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
14433 {
14434  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
14435  bool ErasedFlag = false;
14436 
14437  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
14438  {
14439  if(PrefDirSize() == 0)
14440  {
14441  Utilities->CallLogPop(1511);
14442  return;
14443  }
14444  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
14445  {
14446  ErasedFlag = false;
14447  // use 'else' to ensure don't try to access an erased element
14448  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
14449  {
14450  ErasePrefDirElementAt(11, x);
14451  ErasedFlag = true;
14452  }
14453  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
14454  {
14455  ErasePrefDirElementAt(12, x);
14456  ErasedFlag = true;
14457  }
14458  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
14459  {
14460  ErasePrefDirElementAt(13, x);
14461  ErasedFlag = true;
14462  }
14463  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
14464  {
14465  ErasePrefDirElementAt(9, x);
14466  ErasedFlag = true;
14467  }
14468  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
14469  {
14470  ErasePrefDirElementAt(10, x);
14471  ErasedFlag = true;
14472  }
14473  if(!ErasedFlag)
14474  {
14475  // don't use 'else' here as may be more than one that need decrementing
14476  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
14477  {
14478  PrefDirVector.at(x).TrackVectorPosition--;
14479  }
14480  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
14481  {
14482  PrefDirVector.at(x).Conn[0]--;
14483  }
14484  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
14485  {
14486  PrefDirVector.at(x).Conn[1]--;
14487  }
14488  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
14489  {
14490  PrefDirVector.at(x).Conn[2]--;
14491  }
14492  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
14493  {
14494  PrefDirVector.at(x).Conn[3]--;
14495  }
14496  }
14497  }
14498  }
14499  Utilities->CallLogPop(1434);
14500 }
14501 
14502 // ---------------------------------------------------------------------------
14503 
14504 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
14505 {
14506  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
14507  OverallDistance = 0;
14508  OverallSpeedLimit = 0;
14509  LeadingPointsAtLastElement = false;
14510  if(PrefDirSize() == 0) // shouldn't be empty when this called
14511  {
14512  Utilities->CallLogPop(1491);
14513  return;
14514  }
14515  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
14516  {
14517  LeadingPointsAtLastElement = true;
14518  Utilities->CallLogPop(1492);
14519  return;
14520  }
14521  for(unsigned int x = 0; x < PrefDirSize(); x++)
14522  {
14523  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
14524  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
14525  {
14526  OverallDistance += PrefDirElement.Length23;
14527  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14528  {
14529  if(x == 0)
14530  {
14531  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
14532  }
14533  else
14534  {
14535  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14536  {
14537  OverallSpeedLimit = -1;
14538  }
14539  }
14540  }
14541  }
14542  else
14543  {
14544  OverallDistance += PrefDirElement.Length01;
14545  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14546  {
14547  if(x == 0)
14548  {
14549  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14550  }
14551  else
14552  {
14553  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14554  {
14555  OverallSpeedLimit = -1;
14556  }
14557  }
14558  }
14559  }
14560  }
14561  Utilities->CallLogPop(1529);
14562 }
14563 
14564 // ---------------------------------------------------------------------------
14565 
14566 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14567 {
14568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14569  if(PrefDirSize() == 0)
14570  {
14571  Utilities->CallLogPop(1564);
14572  return;
14573  }
14574  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14575  bool FoundFlag;
14577  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14578 
14579  while(MMIT != PrefDir4MultiMap.end())
14580  {
14581  HLoc = MMIT->first.first;
14582  VLoc = MMIT->first.second;
14583  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14584  H = HLoc - Track->GetHLocMin();
14585  V = VLoc - Track->GetVLocMin();
14586  // always found in order, any missing have PrefDirPosx == -1
14587  if(PrefDirPos0 > -1)
14588  {
14589  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14590  }
14591  if(PrefDirPos1 > -1)
14592  {
14593  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14594  }
14595  if(PrefDirPos2 > -1)
14596  {
14597  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
14598  }
14599  if(PrefDirPos3 > -1)
14600  {
14601  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
14602  }
14603  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
14604  {
14605  // need to plot all 4 in order to obtain all the direction graphics
14606  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14607  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14608  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14609  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14610  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14611  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14612  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
14613  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
14614  MMIT++;
14615  MMIT++;
14616  MMIT++;
14617  MMIT++;
14618  }
14619  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14620  {
14621  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14622  {
14623  // 0 & 1 constitute the bidirectional PrefDir
14624  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14625  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14626  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14627  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14628  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
14629  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
14630  MMIT++;
14631  MMIT++;
14632  MMIT++;
14633  }
14634  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
14635  {
14636  // 0 & 2 constitute the bidirectional PrefDir
14637  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14638  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14639  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14640  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14641  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14642  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14643  MMIT++;
14644  MMIT++;
14645  MMIT++;
14646  }
14647  else
14648  {
14649  // 1 & 2 constitute the bidirectional PrefDir
14650  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14651  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14652  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
14653  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
14654  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14655  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14656  MMIT++;
14657  MMIT++;
14658  MMIT++;
14659  }
14660  }
14661  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14662  {
14663  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
14664  {
14665  // 0 & 1 constitute the bidirectional PrefDir
14666  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
14667  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
14668  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
14669  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
14670  MMIT++;
14671  MMIT++;
14672  }
14673  else
14674  {
14675  // 2 unidirectional PrefDirs
14676  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14677  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14678  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
14679  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
14680  MMIT++;
14681  MMIT++;
14682  }
14683  }
14684  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
14685  {
14686  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
14687  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
14688  MMIT++;
14689  }
14690  }
14691  Utilities->CallLogPop(1565);
14692 }
14693 
14694 // ---------------------------------------------------------------------------
14695 
14696 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
14697 /*
14698  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
14699  level crossing, signals with wrong direction set, or buffers.
14700 */
14701 {
14702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
14703  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14704  bool FoundFlag;
14706  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14707 
14708  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
14709  ElementIn.VLoc)))
14710  {
14711  Utilities->CallLogPop(1982);
14712  return(false);
14713  }
14714  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
14715  {
14716  Utilities->CallLogPop(1983);
14717  return(false);
14718  }
14719 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
14720  {
14721  Utilities->CallLogPop(1995);
14722  return(false);
14723  }
14724 */
14725 // Now check that there is only a single prefdir set
14726  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14727 // always found in order, any missing have PrefDirPosx == -1
14728  if(PrefDirPos0 > -1)
14729  {
14730  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14731  }
14732  if(PrefDirPos1 > -1)
14733  {
14734  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
14735  }
14736  if(PrefDirPos2 > -1)
14737  {
14738  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
14739  }
14740  if(PrefDirPos3 > -1)
14741  {
14742  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
14743  }
14744  if(PrefDirPos3 > -1) // 4 found, all bidirectional
14745  {
14746  Utilities->CallLogPop(1984);
14747  return(false);
14748  }
14749  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
14750  {
14751  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
14752  {
14753  Utilities->CallLogPop(1985);
14754  return(false);
14755  }
14756  else
14757  {
14758  Utilities->CallLogPop(1986);
14759  return(true);
14760  }
14761  }
14762  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
14763  {
14764  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
14765  {
14766  Utilities->CallLogPop(1987);
14767  return(false);
14768  }
14769  else
14770  {
14771  Utilities->CallLogPop(1988);
14772  return(true);
14773  }
14774  }
14775  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
14776  {
14777  if(PrefDirElement0.XLinkPos == EntryPos)
14778  {
14779  Utilities->CallLogPop(1989);
14780  return(false);
14781  }
14782  else
14783  {
14784  Utilities->CallLogPop(1990);
14785  return(true);
14786  }
14787  }
14788  else
14789  {
14790  Utilities->CallLogPop(1991);
14791  return(false); // none found
14792  }
14793 }
14794 
14795 // ---------------------------------------------------------------------------
14796 
14798 {
14799 /* //Added at v2.1.0
14800  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
14801  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
14802  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
14803  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
14804  and can be modelled better anyway.
14805 
14806  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
14807  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
14808  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14809  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14810  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14811  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14812 */
14813  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
14814  ElementIn.VLoc + "," + XLink);
14815  int TrackVecPos;
14816  bool TrackFoundFlag;
14817  TTrackElement TempTrackElement;
14818 
14819  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
14820  {
14821  Utilities->CallLogPop(2047);
14822  return(false);
14823  }
14824 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
14825  if(XLink == 1)
14826  {
14827  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14828  if(TrackFoundFlag)
14829  {
14830  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
14831  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14832  {
14833  Utilities->CallLogPop(2048);
14834  return(true);
14835  }
14836  }
14837  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14838  if(TrackFoundFlag)
14839  {
14840  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
14841  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14842  {
14843  Utilities->CallLogPop(2049);
14844  return(true);
14845  }
14846  }
14847  }
14848 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
14849  if(XLink == 3)
14850  {
14851  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14852  if(TrackFoundFlag)
14853  {
14854  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
14855  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14856  {
14857  Utilities->CallLogPop(2050);
14858  return(true);
14859  }
14860  }
14861  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
14862  if(TrackFoundFlag)
14863  {
14864  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
14865  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14866  {
14867  Utilities->CallLogPop(2051);
14868  return(true);
14869  }
14870  }
14871  }
14872 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
14873  if(XLink == 7)
14874  {
14875  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
14876  if(TrackFoundFlag)
14877  {
14878  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
14879  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
14880  {
14881  Utilities->CallLogPop(2052);
14882  return(true);
14883  }
14884  }
14885  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14886  if(TrackFoundFlag)
14887  {
14888  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
14889  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
14890  {
14891  Utilities->CallLogPop(2053);
14892  return(true);
14893  }
14894  }
14895  }
14896 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
14897  if(XLink == 9)
14898  {
14899  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
14900  if(TrackFoundFlag)
14901  {
14902  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
14903  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
14904  {
14905  Utilities->CallLogPop(2054);
14906  return(true);
14907  }
14908  }
14909  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
14910  if(TrackFoundFlag)
14911  {
14912  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
14913  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
14914  {
14915  Utilities->CallLogPop(2055);
14916  return(true);
14917  }
14918  }
14919  }
14920  Utilities->CallLogPop(2056);
14921  return(false);
14922 }
14923 
14924 // ---------------------------------------------------------------------------
14925 
14926 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
14927 {
14928 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
14929  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
14930  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
14931  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
14932  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
14933 */
14934  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
14936  bool FoundFlag, ContFlag, FoundElements = false;
14937  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14938  TPrefDirElement NextElement;
14939 
14940  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
14941  {
14942  LastIteratorValue++;
14943  ContFlag = false;
14944  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
14945  {
14946  continue;
14947  }
14948 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
14949  {
14950  continue;
14951  }
14952 */
14953 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
14954  // found a potential route start point
14955  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
14956  {
14957  continue;
14958  }
14959  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
14960  {
14961  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
14962  if(PDVIt->TrackType == Continuation)
14963  {
14964  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
14965  {
14966  continue;
14967  }
14968  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
14969  {
14970  continue;
14971  }
14972  }
14973  StartElement = *PDVIt;
14974 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
14975  // diverging track on which there was no pref dir. See below for 2 required changes.
14976  }
14977  else
14978  {
14979  continue;
14980  }
14981  // now track along until find a signal or continuation, checking validity for each element
14982  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
14983  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
14984  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14985  if(PrefDirPos0 == -1) // no continuing prefdir
14986  {
14987  continue;
14988  }
14989  bool NextElementFoundFlag = false;
14990  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14991  {
14992  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
14993  NextElementFoundFlag = true;
14994  }
14995  if(PrefDirPos1 > -1)
14996  {
14997  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
14998  {
14999  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
15000  NextElementFoundFlag = true;
15001  }
15002  }
15003  if(PrefDirPos2 > -1)
15004  {
15005  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15006  {
15007  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
15008  NextElementFoundFlag = true;
15009  }
15010  }
15011  if(PrefDirPos3 > -1)
15012  {
15013  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15014  {
15015  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
15016  NextElementFoundFlag = true;
15017  }
15018  }
15019  if(!NextElementFoundFlag)
15020  {
15021  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15022 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
15023  }
15024  while(true)
15025  {
15026  // check validity
15027  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
15028  {
15029  ContFlag = true;
15030  break;
15031  }
15032  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
15033  {
15034  ContFlag = true;
15035  break;
15036  }
15037  // check if in a route, providing not a signal, as a signal might be at the start of a route
15038  if(NextElement.TrackType != SignalPost)
15039  {
15040  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
15041  {
15042  ContFlag = true;
15043  break;
15044  }
15045  }
15046  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
15047  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
15048  {
15049  EndElement = NextElement;
15050  break;
15051  }
15052  // get the next element in the sequence
15053  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
15054  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
15055  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15056  if(PrefDirPos0 == -1) // no continuing prefdir
15057  {
15058  ContFlag = true;
15059  break;
15060  }
15061  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15062  {
15063  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
15064  continue;
15065  }
15066  if(PrefDirPos1 > -1)
15067  {
15068  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15069  {
15070  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
15071  continue;
15072  }
15073  }
15074  if(PrefDirPos2 > -1)
15075  {
15076  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15077  {
15078  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
15079  continue;
15080  }
15081  }
15082  if(PrefDirPos3 > -1)
15083  {
15084  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15085  {
15086  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
15087  continue;
15088  }
15089  }
15090  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
15091  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
15092  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
15093  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
15094  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
15095  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
15096  {
15097  ContFlag = true;
15098  break;
15099  }
15100  else
15101  {
15102  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15103  // could drop the bridge test but keep it to show the change history
15104  break;
15105 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
15106  }
15107  }
15108  if(ContFlag)
15109  {
15110  continue;
15111  }
15112  // else have start and end elements set & all elements valid, so set up the route segment
15113  FoundElements = true;
15114  break;
15115  }
15116  if(FoundElements)
15117  {
15118  Utilities->CallLogPop(1992);
15119  return(true);
15120  }
15121  else
15122  {
15123  Utilities->CallLogPop(1993);
15124  return(false);
15125  }
15126 }
15127 
15128 // ---------------------------------------------------------------------------
15129 // TOneRoute
15130 // ---------------------------------------------------------------------------
15131 
15132 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
15133 {
15134 /* General:
15135  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
15136  containing all the new elements to form the route. When complete, the SearchVector is converted into route
15137  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
15138  route will use automatic signals or not.
15139  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
15140  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
15141  elements, so additional work is needed to complete all their members before they are ready for conversion into
15142  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
15143  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
15144  ConvertAndAdd.......
15145 */
15146  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15147  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
15148  ClearRoute();
15149  int TrackVectorPosition;
15150  TTrackElement TrackElement;
15151  TPrefDirElement FirstElement, LastElement;
15152 
15153  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15154  {
15155  Utilities->CallLogPop(199);
15156  return(false);
15157  }
15158  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
15159  {
15160  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
15161  Utilities->CallLogPop(1996);
15162  return(false);
15163  }
15164  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15165  {
15166  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation to start or add to a route, or points to change them");
15167  Utilities->CallLogPop(200);
15168  return(false);
15169  }
15170  if(Track->IsLCAtHV(18, HLoc, VLoc))
15171  {
15172  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
15173  Utilities->CallLogPop(1909);
15174  return(false);
15175  }
15176 // check if selected a train & disallow if so
15177  if(TrackElement.TrainIDOnElement > -1)
15178  {
15179  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
15180  Utilities->CallLogPop(202);
15181  return(false);
15182  }
15183 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15184  TPrefDirElement PrefDirElement;
15185  int LockedVectorNumber;
15186 
15187  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15188  {
15189  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
15190  Utilities->CallLogPop(203);
15191  return(false);
15192  }
15193  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15194  {
15195  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
15196  Utilities->CallLogPop(204);
15197  return(false);
15198  }
15200  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
15201 // signal in an autosig route & follow with a non-autosig route
15202 
15203  TPrefDirElement BlankElement;
15204 
15205  StartElement1 = BlankElement;
15206  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
15207 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
15208  bool InPrefDirFlag = false;
15209 
15210  bool FoundFlag;
15211  int PrefDirPos0 = -1;
15212  int PrefDirPos1 = -1;
15213  int PrefDirPos2 = -1;
15214  int PrefDirPos3 = -1;
15215 
15217  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15218  int PrefDirVecPos[4] =
15219  {
15220  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15221  };
15222 
15223  for(int x = 0; x < 4; x++)
15224  {
15225  int b = PrefDirVecPos[x];
15226  if(b > -1)
15227  {
15228  // only allow the appropriate exit route to be searched
15229  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
15230  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
15231  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
15232  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
15233  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
15234  {
15235  InPrefDirFlag = true;
15236  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
15237  if(AutoSigsFlag)
15238  {
15239  StartElement1.AutoSignals = true;
15240  }
15241  StartElement1.PrefDirRoute = true;
15242  }
15243  }
15244  }
15245 
15246  if(!InPrefDirFlag)
15247  {
15248  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15249  Utilities->CallLogPop(205);
15250  return(false);
15251  }
15252 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
15254  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15255 
15256  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
15257  {
15258  throw Exception("Selection in two routes - should never happen!");
15259  }
15260  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
15261  {
15262  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15263  {
15264  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
15265  Utilities->CallLogPop(206);
15266  return(false);
15267  }
15268  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
15269  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15270  {
15271  TrainController->StopTTClockMessage(14, "No forward connection from this position");
15272  Utilities->CallLogPop(207);
15273  return(false);
15274  }
15275  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
15276  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15277  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15278  { //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
15279 // TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
15280 // Utilities->CallLogPop(208);
15281 // return(false);
15282  }
15283  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
15285  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
15286  if(AutoSigsFlag)
15287  {
15288  StartElement1.AutoSignals = true;
15289  }
15290  StartElement1.PrefDirRoute = true;
15292  Utilities->CallLogPop(209);
15293  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
15294  }
15295 
15296  else // no route started
15297  {
15298 // check if selected position is adjacent to start or end of an existing route and disallow
15299  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15300  {
15301  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
15302  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15303  {
15304  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
15305  Utilities->CallLogPop(210);
15306  return(false);
15307  }
15308  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15309  {
15310  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
15311  Utilities->CallLogPop(211);
15312  return(false);
15313  }
15314  }
15315 
15316 // check if it's adjacent to end of an existing route,
15317  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15318  {
15320  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15321  {
15322  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
15323  Utilities->CallLogPop(212);
15324  return(false);
15325  }
15326  }
15327  SearchVector.push_back(StartElement1);
15328  Utilities->CallLogPop(213);
15329  return(true);
15330  }
15331 }
15332 
15333 // ---------------------------------------------------------------------------
15334 
15335 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
15336  IDInt &ReqPosRouteID, bool &PointsChanged)
15337 
15338 /*
15339  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
15340 
15341  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
15342  this being set to -1 for not used.
15343  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
15344  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
15345  Check correct type of element - signal/buffers/continuation.
15346  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
15347  EndElement2 corresponding to the 2 possible PrefDir elements).
15348  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
15349  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
15350  linked forward to another route.
15351  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
15352  for same position as start should cover this)
15353 
15354  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
15355  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
15356  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
15357  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
15358  If the search fails then return false.
15359  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
15360  in the SearchVector to ensure it's entered as part of the new route.
15361  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
15362  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
15363  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
15364  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
15365  so return false, with an appropriate message if ConsecSignalsRoute set.
15366 */
15367 
15368 {
15369  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
15370  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
15371  int EndPosition; // the position selected
15372  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
15373 
15374  Track->LCFoundInAutoSigsRoute = false;
15376  TotalSearchCount = 0;
15377  ReqPosRouteID = IDInt(-1); // default value for not used
15378  TTrackElement TrackElement;
15379  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
15380  // given element as can't select 2-track elements
15381  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15382  {
15383  Utilities->CallLogPop(214);
15384  return(false);
15385  }
15386  if(Track->IsLCAtHV(19, HLoc, VLoc))
15387  {
15388  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
15389  Utilities->CallLogPop(1908);
15390  return(false);
15391  }
15392 // cancel selection if on original start element
15393  if(EndPosition == StartRoutePosition)
15394  {
15395  Utilities->CallLogPop(215);
15396  return(false);
15397  }
15398  if(AutoSigsFlag)
15399  {
15400  if(TrackElement.TrackType == Buffers)
15401  {
15402  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
15403  Utilities->CallLogPop(216);
15404  return(false);
15405  }
15406  }
15407  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15408  {
15409  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
15410  Utilities->CallLogPop(217);
15411  return(false);
15412  }
15413 // check if train on element
15414  if(TrackElement.TrainIDOnElement > -1)
15415  {
15416  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
15417  Utilities->CallLogPop(219);
15418  return(false);
15419  }
15420 // disallow if not in EveryPrefDir & set EndElement(s)
15421  bool InPrefDirFlag = false;
15422 
15423  bool FoundFlag;
15424  int PrefDirPos0 = -1;
15425  int PrefDirPos1 = -1;
15426  int PrefDirPos2 = -1;
15427  int PrefDirPos3 = -1;
15428 
15429  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
15430  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15431  int PrefDirVecPos[4] =
15432  {
15433  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15434  };
15435 
15436  for(int x = 0; x < 4; x++)
15437  {
15438  int b = PrefDirVecPos[x];
15439  if(b > -1)
15440  {
15441  InPrefDirFlag = true;
15442  if(EndElement1.TrackVectorPosition == -1)
15443  {
15444  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
15445  }
15446  else
15447  {
15448  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
15449  }
15450  }
15451  }
15452  if(!InPrefDirFlag)
15453  {
15454  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15455  Utilities->CallLogPop(220);
15456  return(false);
15457  }
15458 // check if in an existing route - can't be a bridge so can use a simple 'find'
15459 // bool InRoute = false;
15461  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15462 
15463  if(RoutePair.first > -1)
15464  {
15465  if(RoutePair.second != 0) // not first element in existing route so no good
15466  {
15467  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
15468  Utilities->CallLogPop(221);
15469  return(false);
15470  }
15471  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
15472 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15473  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
15474  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15475  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
15476  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15477  {
15478  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
15479  Utilities->CallLogPop(222);
15480  return(false);
15481  }
15482  EndElement1 = RouteElement;
15483  EndElement2 = BlankElement; // only need the route element
15484  EndPosition = EndElement1.TrackVectorPosition;
15485  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
15486  }
15487 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15488 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15489 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15490 
15491  if(EndElement1.HLoc >= StartElement1.HLoc)
15492  {
15494  SearchLimitHighH = EndElement1.HLoc + 15;
15495  }
15496  else
15497  {
15498  SearchLimitLowH = EndElement1.HLoc - 15;
15500  }
15501  if(EndElement1.VLoc >= StartElement1.VLoc)
15502  {
15504  SearchLimitHighV = EndElement1.VLoc + 15;
15505  }
15506  else
15507  {
15508  SearchLimitLowV = EndElement1.VLoc - 15;
15510  }
15511 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15512  check & TotalSearchCounts check
15513  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15514  {
15515  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
15516  Utilities->CallLogPop(1693);
15517  return false;
15518  }
15519 */
15520 // check if adjacent to start and disallow
15521  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15522  {
15524  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
15525 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
15526 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
15527  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15528  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15529  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
15530  {
15531  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
15532  Utilities->CallLogPop(223);
15533  return(false);
15534  }
15535 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15536 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15537  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15538  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15539  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15540  {
15541  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15542  Utilities->CallLogPop(224);
15543  return(false);
15544  }
15545 // check if adjacent to end of a route & disallow
15547  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15548  {
15549  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15550  Utilities->CallLogPop(225);
15551  return(false);
15552  }
15553  }
15554 
15555 // check for same route as start element
15557  {
15558  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15559  Utilities->CallLogPop(226);
15560  return(false);
15561  }
15562 // check for a looping route
15563  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15564  {
15566  {
15567  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15568  Utilities->CallLogPop(1844);
15569  return(false);
15570  }
15571  }
15572 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15573 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15574 // and don't want to add it again
15575  if(StartSelectionRouteID > -1)
15576  {
15577  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15578  AutoSigsFlag, false))
15579  {
15580  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
15581  if(PointsToBeChanged(5, NewFailedPointsTVPos))
15582  {
15583  if(NewFailedPointsTVPos > -1)
15584  {
15585  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
15586  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
15587  " failed during route setting.");
15588  Utilities->CallLogPop(2488);
15589  return(false);
15590  }
15591  PointsChanged = true;
15592  }
15593  Utilities->CallLogPop(227);
15594  return(true);
15595  }
15596  else if(!Track->SuppressRouteFailMessage)
15597  {
15598  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
15600  Utilities->CallLogPop(228);
15601  return(false);
15602  }
15603  }
15604  else
15605  {
15606 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
15607 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
15608 
15609 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
15610 // note that a blank element will have XLinkPos set to -1
15611  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
15612  {
15613  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15614  AutoSigsFlag, false))
15615  {
15616  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
15617  if(PointsToBeChanged(6, NewFailedPointsTVPos))
15618  {
15619  if(NewFailedPointsTVPos > -1)
15620  {
15621  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
15622  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
15623  " failed during route setting.");
15624  Utilities->CallLogPop(2490);
15625  return(false);
15626  }
15627  PointsChanged = true;
15628  }
15629  Utilities->CallLogPop(229);
15630  return(true);
15631  }
15632  else
15633  {
15635  {
15637  }
15638  Utilities->CallLogPop(230);
15639  return(false);
15640  }
15641  }
15642  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
15643  {
15644  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15645  AutoSigsFlag, false))
15646  {
15647  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
15648  if(PointsToBeChanged(7, NewFailedPointsTVPos))
15649  {
15650  if(NewFailedPointsTVPos > -1)
15651  {
15652  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
15653  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
15654  " failed during route setting.");
15655  Utilities->CallLogPop(2492);
15656  return(false);
15657  }
15658  PointsChanged = true;
15659  }
15660  Utilities->CallLogPop(231);
15661  return(true);
15662  }
15663  else
15664  {
15666  {
15668  }
15669  Utilities->CallLogPop(232);
15670  return(false);
15671  }
15672  }
15673  // now start off in the best direction
15674  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
15675  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
15676  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
15677  // unless new problems are found.
15678  if(StartElement1.XLinkPos == BestPos)
15679  {
15680  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15681  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15682  AutoSigsFlag, false))
15683  {
15684  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
15685  if(PointsToBeChanged(8, NewFailedPointsTVPos))
15686  {
15687  if(NewFailedPointsTVPos > -1)
15688  {
15689  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
15690  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
15691  " failed during route setting.");
15692  Utilities->CallLogPop(2494);
15693  return(false);
15694  }
15695  PointsChanged = true;
15696  }
15697  Utilities->CallLogPop(233);
15698  return(true);
15699  }
15700  else if(StartElement2.TrackVectorPosition > -1)
15701  {
15702  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15703  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15704  AutoSigsFlag, false))
15705  {
15706  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
15707  if(PointsToBeChanged(9, NewFailedPointsTVPos))
15708  {
15709  if(NewFailedPointsTVPos > -1)
15710  {
15711  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
15712  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
15713  " failed during route setting.");
15714  Utilities->CallLogPop(2496);
15715  return(false);
15716  }
15717  PointsChanged = true;
15718  }
15719  Utilities->CallLogPop(234);
15720  return(true);
15721  }
15722  }
15723  }
15724  else if(StartElement2.TrackVectorPosition > -1)
15725  {
15726  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15727  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15728  AutoSigsFlag, false))
15729  {
15730  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
15731  if(PointsToBeChanged(10, NewFailedPointsTVPos))
15732  {
15733  if(NewFailedPointsTVPos > -1)
15734  {
15735  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
15736  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
15737  " failed during route setting.");
15738  Utilities->CallLogPop(2498);
15739  return(false);
15740  }
15741  PointsChanged = true;
15742  }
15743  Utilities->CallLogPop(1857);
15744  return(true);
15745  }
15746  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15747  AutoSigsFlag, false))
15748  {
15749  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
15750  if(PointsToBeChanged(11, NewFailedPointsTVPos))
15751  {
15752  if(NewFailedPointsTVPos > -1)
15753  {
15754  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
15755  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
15756  " failed during route setting.");
15757  Utilities->CallLogPop(2500);
15758  return(false);
15759  }
15760  PointsChanged = true;
15761  }
15762  Utilities->CallLogPop(1858);
15763  return(true);
15764  }
15765  }
15766  else if(StartElement1.XLinkPos == (1 - BestPos))
15767  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
15768  {
15769  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15770  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15771  AutoSigsFlag, false))
15772  {
15773  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
15774  if(PointsToBeChanged(12, NewFailedPointsTVPos))
15775  {
15776  if(NewFailedPointsTVPos > -1)
15777  {
15778  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
15779  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
15780  " failed during route setting.");
15781  Utilities->CallLogPop(2502);
15782  return(false);
15783  }
15784  PointsChanged = true;
15785  }
15786  Utilities->CallLogPop(1864);
15787  return(true);
15788  }
15789  }
15790  }
15792  {
15794  }
15795  Utilities->CallLogPop(235);
15796  return(false);
15797 }
15798 
15799 // ---------------------------------------------------------------------------
15800 
15801 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
15802 {
15803  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
15804  if(PrefDirSize() == 0)
15805  {
15806  Utilities->CallLogPop(1704);
15807  return;
15808  }
15809  for(unsigned int x = 0; x < PrefDirSize(); x++)
15810  {
15811  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
15812  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
15813  {
15814  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15815  TempPrefDirElement.EXGraphicPtr);
15816  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
15817  {
15818  if(x == 0)
15819  {
15820  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15821  TempPrefDirElement.EntryDirectionGraphicPtr);
15822  }
15823  if(x == (PrefDirSize() - 1))
15824  {
15825  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
15826  TempPrefDirElement.EntryDirectionGraphicPtr);
15827  }
15828  }
15829  }
15830  }
15831 
15832  Utilities->CallLogPop(1705);
15833 }
15834 
15835 // ---------------------------------------------------------------------------
15836 
15837 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
15838  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
15839 /*
15840  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
15841  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
15842  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
15843  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
15844  Return false if any element (apart from RequiredPosition) is on an existing route.
15845  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
15846 
15847  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
15848  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
15849  added during the function so as to leave it exactly as it was on entering, then return false).
15850  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
15851  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
15852  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
15853  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
15854  the route number that the searched-for element is the start of if any, and set to -1 if no
15855  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
15856  this unit, together with the ConsecSignals and AutoSigsFlag flags.
15857  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
15858  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
15859 
15860  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
15861  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
15862  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
15863  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
15864  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
15865  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
15866  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15867  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
15868  or if train on element (unless a bridge & train on different track).
15869  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
15870  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
15871  a leading point where both trailing directions are in EveryPrefDir, if not fail.
15872  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
15873  AutoSignals member set if AutoSigsFlag set, then return true.
15874  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
15875 
15876  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
15877  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
15878  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
15879  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
15880  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
15881  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
15882  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
15883 
15884  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
15885  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
15886 */
15887 
15888 {
15889  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
15890  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
15891  AnsiString((short)AutoSigsFlag) + "," + AnsiString((short)RecursiveCall));
15892  int VectorCount = 0;
15893  if(!RecursiveCall) //added at v2.15.1
15894  {
15896  }
15897 
15898  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
15899 
15900 // check for a fouled diagonal for first element. Added for v1.3.2
15901  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
15902  {
15903  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
15904  {
15905  for(int x = 0; x < VectorCount; x++)
15906  {
15907  SearchVector.erase(SearchVector.end() - 1);
15908  }
15909  Utilities->CallLogPop(2043);
15910  return(false);
15911  }
15912  }
15913  bool FirstPass = true;
15914 
15915  while(true)
15916  {
15917  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
15918  {
15919  Track->LCFoundInAutoSigsRoute = true;
15920  }
15921  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
15922  {
15923  for(int x = 0; x < VectorCount; x++)
15924  {
15925  SearchVector.erase(SearchVector.end() - 1);
15926  }
15927  Utilities->CallLogPop(1926);
15928  return(false);
15929  }
15930  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
15931  {
15932  for(int x = 0; x < VectorCount; x++)
15933  {
15934  SearchVector.erase(SearchVector.end() - 1);
15935  }
15936  Utilities->CallLogPop(236);
15937  return(false);
15938  }
15939  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
15940  // reached a valid signal that isn't the required position, user should always select the next
15941  // signal in a route when ConsecSignals is true so have to fail
15942  // won't affect recurive searches as for them the first pass element is always a point
15943  {
15944  for(int x = 0; x < VectorCount; x++)
15945  {
15946  SearchVector.erase(SearchVector.end() - 1);
15947  }
15948  Utilities->CallLogPop(237);
15949  return(false);
15950  }
15951  FirstPass = false;
15952  int NextPosition = PrefDirElement.Conn[XLinkPos];
15953  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
15954  TPrefDirElement SearchElement(NextTrackElement);
15955  SearchElement.TrackVectorPosition = NextPosition;
15956  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
15957  SearchElement.ELinkPos = NextELinkPos;
15958  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
15959  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
15960  int NextXLinkPos;
15961  if(SearchElement.ELinkPos == 0)
15962  {
15963  NextXLinkPos = 1;
15964  }
15965  if(SearchElement.ELinkPos == 1)
15966  {
15967  NextXLinkPos = 0;
15968  }
15969  if(SearchElement.ELinkPos == 2)
15970  {
15971  NextXLinkPos = 3;
15972  }
15973  if(SearchElement.ELinkPos == 3)
15974  {
15975  NextXLinkPos = 2;
15976  }
15977  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15978  {
15979  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15980 // note that may be buffers, continuation or gap
15981  SearchElement.XLinkPos = NextXLinkPos;
15982  }
15983 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
15984 
15985 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15986  drop this at v2.16.1 as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of points and
15987  crossovers as can reach element on opposite track and still find the required end point - causes error when adding to the Route2MultiMap
15988  (happened by chance when developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search
15989  through all searchvector.
15990 
15991  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
15992 */
15993  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
15994  {
15995  for(unsigned int x = 0; x < SearchVector.size(); x++)
15996  {
15997  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
15998  {
15999  for(int x = 0; x < VectorCount; x++)
16000  {
16001  SearchVector.erase(SearchVector.end() - 1);
16002  }
16003  Utilities->CallLogPop(2653);
16004  return(false);
16005  }
16006  }
16007  }
16008  else if(SearchElement.TrackType == Bridge)
16009  {
16010  for(unsigned int x = 0; x < SearchVector.size(); x++)
16011  {
16012  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
16013  (SearchElement.ELink == SearchVector.at(x).ELink))
16014  {
16015  for(int x = 0; x < VectorCount; x++)
16016  {
16017  SearchVector.erase(SearchVector.end() - 1);
16018  }
16019  Utilities->CallLogPop(2654);
16020  return(false);
16021  }
16022  }
16023  }
16024 
16025 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16026  TAllRoutes::TRouteElementPair SecondPair;
16028  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16029  if(RoutePair.first > -1)
16030  {
16031  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16032  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
16033  RoutePair.second).ELinkPos)))
16034  {
16035  // still OK if start of an expected route
16036  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
16037  {
16038  for(int x = 0; x < VectorCount; x++)
16039  {
16040  SearchVector.erase(SearchVector.end() - 1);
16041  }
16042  Utilities->CallLogPop(239);
16043  return(false); // only allow for start of an expected route
16044  }
16045  }
16046  }
16047  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16048  {
16049  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16050  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
16051  SecondPair.second).ELinkPos)))
16052  {
16053  // still OK if start of an expected route
16054  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
16055  {
16056  for(int x = 0; x < VectorCount; x++)
16057  {
16058  SearchVector.erase(SearchVector.end() - 1);
16059  }
16060  Utilities->CallLogPop(240);
16061  return(false); // only allow for start of an expected route
16062  }
16063  }
16064  }
16065 // check if a train on element, unless a bridge & train on different track
16066 // OK of same train as start element - no drop this
16067 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16068  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16069  {
16070  for(int x = 0; x < VectorCount; x++)
16071  {
16072  SearchVector.erase(SearchVector.end() - 1);
16073  }
16074  Utilities->CallLogPop(241);
16075  return(false);
16076  }
16077  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16078  {
16079  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16080  {
16081  for(int x = 0; x < VectorCount; x++)
16082  {
16083  SearchVector.erase(SearchVector.end() - 1);
16084  }
16085  Utilities->CallLogPop(242);
16086  return(false);
16087  }
16088  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16089  {
16090  for(int x = 0; x < VectorCount; x++)
16091  {
16092  SearchVector.erase(SearchVector.end() - 1);
16093  }
16094  Utilities->CallLogPop(243);
16095  return(false);
16096  }
16097  }
16098 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
16099  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16100  {
16101  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16102  {
16103  for(int x = 0; x < VectorCount; x++)
16104  {
16105  SearchVector.erase(SearchVector.end() - 1);
16106  }
16107  Utilities->CallLogPop(244);
16108  return(false);
16109  }
16110  }
16111 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
16112 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
16113  bool InPrefDirFlag = false;
16114  PrefDirElement1 = BlankElement;
16115  PrefDirElement2 = BlankElement;
16116 
16117  bool FoundFlag;
16118  int PrefDirPos0 = -1;
16119  int PrefDirPos1 = -1;
16120  int PrefDirPos2 = -1;
16121  int PrefDirPos3 = -1;
16123  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
16124  int PrefDirVecPos[4] =
16125  {
16126  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
16127  };
16128  for(int x = 0; x < 4; x++)
16129  {
16130  int b = PrefDirVecPos[x];
16131  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
16132  {
16133  InPrefDirFlag = true;
16134  if(PrefDirElement1.TrackVectorPosition == -1)
16135  {
16136  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
16137  }
16138  else
16139  {
16140  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
16141  }
16142  }
16143  }
16144  if(!InPrefDirFlag)
16145  {
16146  for(int x = 0; x < VectorCount; x++)
16147  {
16148  SearchVector.erase(SearchVector.end() - 1);
16149  }
16150  Utilities->CallLogPop(245);
16151  return(false);
16152  }
16153 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16154 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16155 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16157  {
16158  for(int x = 0; x < VectorCount; x++)
16159  {
16160  SearchVector.erase(SearchVector.end() - 1);
16161  }
16162  Utilities->CallLogPop(1690);
16163  return(false);
16164  }
16165 // check if found it
16166  if(SearchElement.TrackVectorPosition == RequiredPosition)
16167  {
16168 // need to ensure a signal/buffer/continuation
16169 // if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End)) dropped at v2.16.1 - may find element round a loop and appear invalid when in fact valid
16170  if((SearchElement.TrackType != SignalPost) && (SearchElement.TrackType != Buffers) && (SearchElement.TrackType != Continuation)) //added at v2.16.1
16171  {
16172  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
16174  for(int x = 0; x < VectorCount; x++)
16175  {
16176  SearchVector.erase(SearchVector.end() - 1);
16177  }
16178  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1 (to stop several same messages being given)
16179  Utilities->CallLogPop(246);
16180  return(false);
16181  } // if((SearchElement.TrackType != SignalPost) &&.......
16182 //need to make sure it's in the right direction
16183  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
16184  { //condition added at v2.16.1
16185  for(int x = 0; x < VectorCount; x++)
16186  {
16187  SearchVector.erase(SearchVector.end() - 1);
16188  }
16189  Utilities->CallLogPop(2627);
16190  return(false);
16191  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal)......
16192 
16193  if(AutoSigsFlag)
16194  {
16195  PrefDirElement1.AutoSignals = true;
16196  }
16197  PrefDirElement1.PrefDirRoute = true;
16199  {
16201  {
16202  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
16204  }
16205  for(int x = 0; x < VectorCount; x++)
16206  {
16207  SearchVector.erase(SearchVector.end() - 1);
16208  }
16209  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1
16210  Utilities->CallLogPop(1928);
16211  return(false);
16212  }
16213  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
16214  VectorCount++; // not really needed but include for tidyness
16215  TotalSearchCount++;
16216  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0. SignalHasFailed returns true if a signal somewhere on the route fails, route not set if so
16217  { //has to be the top level call (!RecursiveCall) as only then is the route sue to be set
16218  for(int x = 0; x < VectorCount; x++)
16219  {
16220  SearchVector.erase(SearchVector.end() - 1);
16221  }
16222  Utilities->CallLogPop(2522);
16223  return(false);
16224  }
16225  Utilities->CallLogPop(247);
16226  return(true);
16227  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
16228 
16229 // check if a buffer or continuation (end of search on this leg if not found by now)
16230  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16231  {
16232  for(int x = 0; x < VectorCount; x++)
16233  {
16234  SearchVector.erase(SearchVector.end() - 1);
16235  }
16236  Utilities->CallLogPop(248);
16237  return(false);
16238  }
16239 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
16241  {
16242  for(int x = 0; x < VectorCount; x++)
16243  {
16244  SearchVector.erase(SearchVector.end() - 1);
16245  }
16246  Utilities->CallLogPop(1420);
16247  return(false);
16248  }
16249 //deal with failed points, added at v2.13.0
16250  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
16251  {
16252  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
16253  {
16254  SearchElement.XLinkPos = 1;
16255  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16256  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16257  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16258  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16259  }
16260  else
16261  {
16262  SearchElement.XLinkPos = 3;
16263  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16264  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16265  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16266  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16267  }
16268  }
16269  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
16270  {
16271  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16272  {
16273  for(int x = 0; x < VectorCount; x++)
16274  {
16275  SearchVector.erase(SearchVector.end() - 1);
16276  }
16277  Utilities->CallLogPop(2514);
16278  return(false);
16279  }
16280  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16281  {
16282  for(int x = 0; x < VectorCount; x++)
16283  {
16284  SearchVector.erase(SearchVector.end() - 1);
16285  }
16286  Utilities->CallLogPop(2515);
16287  return(false);
16288  }
16289  }
16290 // check if reached a non-failed leading point
16291  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
16292  {
16293 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16294  int SearchPos1 = SearchElement.Attribute + 1;
16295  int SearchPos2;
16296  if(SearchPos1 == 2)
16297  {
16298  SearchPos1++;
16299  }
16300  if(SearchPos1 == 1)
16301  {
16302  SearchPos2 = 3;
16303  }
16304  else
16305  {
16306  SearchPos2 = 1;
16307  }
16308  SearchElement.XLink = SearchElement.Link[SearchPos1];
16309  SearchElement.XLinkPos = SearchPos1;
16310  InPrefDirFlag = false;
16311  if(SearchElement.XLink == PrefDirElement1.XLink)
16312  {
16313  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16314  InPrefDirFlag = true;
16315  }
16316  else if(SearchElement.XLink == PrefDirElement2.XLink)
16317  {
16318  SearchElement = PrefDirElement2;
16319  InPrefDirFlag = true;
16320  }
16321 // push element with XLink set to position [SearchPos1] if on a PrefDir
16322  if(InPrefDirFlag)
16323  {
16324 // check for a fouled diagonal for leading point for XLinkPos == 1)
16325  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16326  {
16327  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16328  {
16329  for(int x = 0; x < VectorCount; x++)
16330  {
16331  SearchVector.erase(SearchVector.end() - 1);
16332  }
16333  Utilities->CallLogPop(249);
16334  return(false);
16335  }
16336  }
16337  if(AutoSigsFlag)
16338  {
16339  SearchElement.AutoSignals = true;
16340  }
16341  SearchElement.PrefDirRoute = true;
16342  SearchVector.push_back(SearchElement);
16343  VectorCount++;
16344  TotalSearchCount++;
16345 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16346  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16347  AutoSigsFlag, true))
16348  {
16350  {
16352  {
16353  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
16355  }
16356  for(int x = 0; x < VectorCount; x++)
16357  {
16358  SearchVector.erase(SearchVector.end() - 1);
16359  }
16360  Utilities->CallLogPop(1929);
16361  return(false);
16362  }
16363  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
16364  {
16365  for(int x = 0; x < VectorCount; x++)
16366  {
16367  SearchVector.erase(SearchVector.end() - 1);
16368  }
16369  Utilities->CallLogPop(2523);
16370  return(false);
16371  }
16372  Utilities->CallLogPop(250);
16373  return(true);
16374  }
16375  else
16376  {
16377 // remove leading point with XLinkPos [1]
16378  if(!QuitAllRecursiveSearchesFlag) //added at v2.15.1
16379  {
16380  SearchVector.erase(SearchVector.end() - 1);
16381  VectorCount--;
16382  }
16383  else
16384  {
16385  for(int x = 0; x < VectorCount; x++)
16386  {
16387  SearchVector.erase(SearchVector.end() - 1);
16388  }
16389  Utilities->CallLogPop(2626);
16390  return(false);
16391  }
16392  }
16393  }
16394 // XLink set to position [SearchPos2]
16395  SearchElement.XLink = SearchElement.Link[SearchPos2];
16396  SearchElement.XLinkPos = SearchPos2;
16397  if(SearchElement.XLink == PrefDirElement1.XLink)
16398  {
16399  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16400  }
16401  else if(SearchElement.XLink == PrefDirElement2.XLink)
16402  {
16403  SearchElement = PrefDirElement2;
16404  }
16405  else // failed to find a valid exit from the point
16406  {
16407  for(int x = 0; x < VectorCount; x++)
16408  {
16409  SearchVector.erase(SearchVector.end() - 1);
16410  }
16411  Utilities->CallLogPop(251);
16412  return(false);
16413  }
16414 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16415  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16416  {
16417  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16418  {
16419  for(int x = 0; x < VectorCount; x++)
16420  {
16421  SearchVector.erase(SearchVector.end() - 1);
16422  }
16423  Utilities->CallLogPop(252);
16424  return(false);
16425  }
16426  }
16427 // push element with XLink set to position [SearchPos2]
16428  if(AutoSigsFlag)
16429  {
16430  SearchElement.AutoSignals = true;
16431  }
16432  SearchElement.PrefDirRoute = true;
16433  SearchVector.push_back(SearchElement);
16434  VectorCount++;
16435  TotalSearchCount++;
16436 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16437  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16438  AutoSigsFlag, true))
16439  {
16441  {
16443  {
16444  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
16446  }
16447  for(int x = 0; x < VectorCount; x++)
16448  {
16449  SearchVector.erase(SearchVector.end() - 1);
16450  }
16451  Utilities->CallLogPop(1930);
16452  return(false);
16453  }
16454  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
16455  {
16456  for(int x = 0; x < VectorCount; x++)
16457  {
16458  SearchVector.erase(SearchVector.end() - 1);
16459  }
16460  Utilities->CallLogPop(2524);
16461  return(false);
16462  }
16463  Utilities->CallLogPop(1592);
16464  return(true);
16465  }
16466  else
16467  {
16468  for(int x = 0; x < VectorCount; x++)
16469  {
16470  SearchVector.erase(SearchVector.end() - 1);
16471  }
16472  Utilities->CallLogPop(253);
16473  return(false);
16474  }
16475  } // if leading point
16476 
16477 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
16478  SearchElement = PrefDirElement1;
16479  if(AutoSigsFlag)
16480  {
16481  SearchElement.AutoSignals = true;
16482  }
16483  SearchElement.PrefDirRoute = true;
16484  SearchVector.push_back(SearchElement);
16485  VectorCount++;
16486  TotalSearchCount++;
16487  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16488  PrefDirElement = SearchElement;
16489  } // while(true)
16490 }
16491 
16492 // ---------------------------------------------------------------------------
16493 
16494 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
16495 {
16496 /*
16497  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
16498  and the new or extended route created from that. Hence action varies depending on whether
16499  it is a completely new route, or an extension of an existing route at the beginning or the end.
16500  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16501  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16502 
16503  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16504  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
16505  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
16506  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
16507  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
16508  is decremented;
16509  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
16510  from the existing route, then enter the new route into the AllRoutesVector;
16511  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16512  then enter the new route into the AllRoutesVector.
16513 
16514  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
16515  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
16516  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
16517  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
16518  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16519  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
16520  for the new route and return;
16521  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
16522  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
16523 
16524  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
16525  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
16526  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
16527 
16528 */
16529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
16530  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
16531  if(SearchVector.size() < 1)
16532  {
16533  Utilities->CallLogPop(254);
16534  return;
16535  }
16537  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
16538  {
16539  Utilities->CallLogPop(255);
16540  return;
16541  }
16542  TAllRoutes::TLockedRouteClass LockedRouteObject;
16543 
16545  unsigned int TruncatePrefDirPosition = 0;
16546 
16547  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
16548 /* if have ReqPosRouteID:
16549  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
16550  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
16551  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
16552  the existing route, then enter the new route into the AllRoutesVector
16553  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16554  then enter the new route into the AllRoutesVector
16555 */
16556  {
16559  {
16560  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
16561  x++) // start at 1 as first element already in SearchVector
16562  {
16564  }
16565  // note that route numbers in map adjusted when ReqPos route cleared
16567  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16568  // set during ClearRouteDuringRouteBuildingAt
16570  {
16573  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16574  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16575  }
16576  }
16578  {
16580  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16581  }
16583  {
16584  SearchVector.pop_back();
16585  }
16586  }
16587  if(StartSelectionRouteID > -1)
16588 /* if have StartSelectionRouteID:
16589  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16590  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
16591  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16592  then add it to the start of the new route, then enter the new route into the AllRoutesVector
16593  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16594 */
16595  {
16597  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16598  {
16601  {
16602  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
16603  for(unsigned int x = 0; x < SearchVector.size(); x++)
16604  {
16606  RouteNumber, GetFixedSearchElementAt(3, x));
16607  // find & store locked route truncate position in PrefDirVector for later use
16609  {
16610  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
16611  {
16612  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
16613  }
16614  }
16615  }
16617  {
16618  throw Exception("Error - failed to validate extended route for preferred route");
16619  }
16622  if(!AutoSigsFlag)
16623  {
16624  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
16625  }
16626  // now add the reinstated locked route if required and set signals accordingly
16628  {
16629  LockedRouteObject.RouteNumber = RouteNumber;
16630  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16631  // now reset the signals for the locked route
16632  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
16633  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16634  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16635  {
16636  // return all signals to red in route section to be truncated
16637  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
16638  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
16639  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16640  {
16641  TrackElement.Attribute = 0;
16642  Track->PlotSignal(10, TrackElement, Display);
16643  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16644  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16645  }
16646  }
16647  }
16648  AllRoutes->CheckMapAndRoutes(1); // test
16649  Utilities->CallLogPop(256);
16650  return;
16651  }
16653  {
16656  RouteElement.AutoSignals = true;
16657  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
16658  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
16659  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
16660  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
16661  }
16662  }
16663  else
16664  {
16666  }
16667 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
16668 // AllRoutesVector hence nothing to do here
16669  }
16670  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
16671  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
16672  {
16673  throw Exception("Error - failed to validate single route for preferred route");
16674  }
16675  AllRoutes->StoreOneRoute(1, this);
16676  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
16677  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
16678  if(!AutoSigsFlag)
16679  {
16680  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
16681  }
16682  AllRoutes->CheckMapAndRoutes(2); // test
16683  Utilities->CallLogPop(257);
16684 }
16685 
16686 // ---------------------------------------------------------------------------
16687 
16688 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
16689 {
16690 /*
16691  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16692  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
16693  & ensure signal/buffers/continuation.
16694  Note that can't select ConsecSignalsRoute for non-preferred routes.
16695  Check if train on element & disallow.
16696  Set default values for retained parameters:-
16697  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
16698  StartSelectionRouteID = route that selection starts in if there is one;
16699 
16700  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
16701  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
16702  validity. This is just for safety reasons, the PrefDir values aren't used.
16703  StartElement1 & 2 are set to these PrefDirelements.
16704 
16705  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
16706 
16707  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
16708  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
16709  blank StartElement2 (only want to use the route element), then return true.
16710  Check if adjacent to start or end of an existing route & disallow if so.
16711  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
16712  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
16713  SetRemainingSearchVectorValues().
16714  Finally add the required element to the SearchVector & return true.
16715 
16716 */
16717  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
16718  AnsiString(VLoc) + "," + AnsiString((short)Callon));
16719  ClearRoute();
16720  int TrackVectorPosition;
16721  TTrackElement TrackElement;
16722  TPrefDirElement FirstElement, LastElement;
16723 
16724  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
16725  {
16726  Utilities->CallLogPop(258);
16727  return(false);
16728  }
16729  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16730  {
16731  if(!Callon)
16732  {
16733  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
16734  }
16735 // makes later adjacent route checks too complicated
16736  Utilities->CallLogPop(259);
16737  return(false);
16738  }
16739  if(Track->IsLCAtHV(21, HLoc, VLoc))
16740  {
16741  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
16742  Utilities->CallLogPop(1910);
16743  return(false);
16744  }
16745 // check if selected a train & disallow if so
16746  if(TrackElement.TrainIDOnElement > -1)
16747  {
16748  if(!Callon)
16749  {
16750  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
16751  }
16752  Utilities->CallLogPop(260);
16753  return(false);
16754  }
16755 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
16756  TPrefDirElement PrefDirElement;
16757  int LockedVectorNumber;
16758 
16759  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
16760  {
16761  if(!Callon)
16762  {
16763  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
16764  }
16765  Utilities->CallLogPop(261);
16766  return(false);
16767  }
16768  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
16769  {
16770  if(!Callon)
16771  {
16772  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
16773  }
16774  Utilities->CallLogPop(262);
16775  return(false);
16776  }
16778 // AdjacentStartRouteNumber = -1;
16779  StartRoutePosition = TrackVectorPosition;
16780 // StartRouteSelectPosition = TrackVectorPosition;
16781 
16782  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
16783  TPrefDirElement PrefDirElement2(TrackElement);
16784 
16785  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
16786  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
16787  TPrefDirElement BlankElement;
16788 
16789  PrefDirElement1.ELinkPos = 0;
16790  PrefDirElement1.XLinkPos = 1;
16791  PrefDirElement1.ELink = PrefDirElement1.Link[0];
16792  PrefDirElement1.XLink = PrefDirElement1.Link[1];
16793  if(!(PrefDirElement1.EntryExitNumber()))
16794  {
16795  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
16796  // no need for bridge check as bridge selections not allowed
16797  }
16798  PrefDirElement1.CheckCount = 9;
16799  PrefDirElement2.ELinkPos = 1;
16800  PrefDirElement2.XLinkPos = 0;
16801  PrefDirElement2.ELink = PrefDirElement2.Link[1];
16802  PrefDirElement2.XLink = PrefDirElement2.Link[0];
16803  if(!(PrefDirElement2.EntryExitNumber()))
16804  {
16805  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
16806  }
16807  PrefDirElement2.CheckCount = 9; // both now set
16808 
16809 // set StartElements to the above PrefDirElements
16810  StartElement1 = PrefDirElement1;
16811  StartElement2 = PrefDirElement2;
16812 
16813 // no PrefDir check needed as doesn't need to be in a PrefDir
16814 
16815 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
16817  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
16818 
16819  if(RoutePair.first > -1)
16820  {
16821  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
16822  {
16823  if(!Callon)
16824  {
16825  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
16826  }
16827  Utilities->CallLogPop(263);
16828  return(false);
16829  }
16830  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
16831  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
16832  {
16833  if(!Callon)
16834  {
16835  TrainController->StopTTClockMessage(39, "No forward connection from this position");
16836  }
16837  Utilities->CallLogPop(264);
16838  return(false);
16839  }
16840  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
16841  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
16842  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
16843  {
16844 // if(!Callon) //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
16845 // {
16846 // TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
16847 // }
16848 // Utilities->CallLogPop(265);
16849 // return(false);
16850  }
16851  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
16853  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
16854  StartElement2 = BlankElement; // only use the route element
16856  Utilities->CallLogPop(266);
16857  return(true); // all retained values set
16858  }
16859 
16860  else // selection not in an existing route
16861  {
16862 // check if it's adjacent to start of an an existing route,
16863  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16864  {
16865  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
16866  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
16867  {
16868  if(!Callon)
16869  {
16870  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
16871  }
16872  Utilities->CallLogPop(267);
16873  return(false);
16874  }
16875  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
16876  {
16877  if(!Callon)
16878  {
16879  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
16880  }
16881  Utilities->CallLogPop(268);
16882  return(false);
16883  }
16884  }
16885 // check if it's adjacent to end of an an existing route,
16886  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
16887  {
16889  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
16890  {
16891  if(!Callon)
16892  {
16893  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
16894  }
16895  Utilities->CallLogPop(269);
16896  return(false);
16897  }
16898  }
16899  // not in a route or adjacent to start or end of a route
16900  // in this case reset all variable values to -1 & CheckCount to 4
16901  StartElement1.ELink = -1;
16902  StartElement1.ELinkPos = -1;
16903  StartElement1.XLink = -1;
16904  StartElement1.XLinkPos = -1;
16905  StartElement1.EXNumber = -1;
16906  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
16907  StartElement2 = BlankElement;
16908  SearchVector.push_back(StartElement1);
16909  Utilities->CallLogPop(270);
16910  return(true);
16911  }
16912 }
16913 
16914 // ---------------------------------------------------------------------------
16915 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
16916 
16917 /*
16918  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
16919 
16920  Declare the following integers:-
16921  EndPosition - TrackVectorPosition for the selection;
16922  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
16923  Check if selection is a valid track element and set EndPosition.
16924  Cancel if select original start element, then check that not points, bridge or crossover.
16925  Check & fail if a train is present at the selection.
16926  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
16927  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
16928  No check needed for selection in EveryPrefDir.
16929  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
16930  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
16931  as don't need it if in a route.
16932  Check if selection adj to start or end of a route and disallow.
16933  Fail if select same route as starting route, though should already have failed earlier if this is so.
16934 
16935  If there's a StartSelectionRouteID then StartElement1 will be set to
16936  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
16937  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
16938  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
16939  to add the new route to the AllRoutesVectorPtr.
16940  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
16941  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
16942  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
16943  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
16944  the search vector values and return.
16945  If not returned yet then have failed to find the required element so return false with no message.
16946 
16947 */
16948 
16949 {
16950 // get EndPosition
16951  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
16952  AnsiString(VLoc));
16953  int EndPosition;
16954  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
16955 
16956  TotalSearchCount = 0;
16957  ReqPosRouteID = IDInt(-1); // for not used
16958  TTrackElement TrackElement;
16959  TPrefDirElement BlankElement;
16961 
16962  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
16963  {
16964  Utilities->CallLogPop(271);
16965  return(false);
16966  }
16967 // EndPosition = EndSelectPosition;
16968 // cancel selection if on original start element
16969  if(EndPosition == StartRoutePosition)
16970  {
16971  Utilities->CallLogPop(272);
16972  return(false);
16973  }
16974  if(Track->IsLCAtHV(22, HLoc, VLoc))
16975  {
16976  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
16977  Utilities->CallLogPop(1911);
16978  return(false);
16979  }
16980  if((TrackElement.TrackType == Points) && !Callon)
16981  {
16982  if(!Callon)
16983  {
16984  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
16985  }
16986 // makes later adjacent route checks too complicated
16987  Utilities->CallLogPop(273);
16988  return(false);
16989  }
16990  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
16991  {
16992  if(!Callon)
16993  {
16994  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
16995  }
16996 // makes later adjacent route checks too complicated
16997  Utilities->CallLogPop(1861);
16998  return(false);
16999  }
17000 // check if train on element
17001  if(TrackElement.TrainIDOnElement > -1)
17002  {
17003  if(!Callon)
17004  {
17005  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
17006  }
17007  Utilities->CallLogPop(274);
17008  return(false);
17009  }
17010 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
17011 // check passed)
17012  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17013  TPrefDirElement EndElement2(TrackElement);
17014 
17015  EndElement1.TrackVectorPosition = EndPosition;
17016  EndElement2.TrackVectorPosition = EndPosition;
17017  EndElement1.ELinkPos = 0;
17018  EndElement1.XLinkPos = 1;
17019  EndElement1.ELink = EndElement1.Link[0];
17020  EndElement1.XLink = EndElement1.Link[1];
17021  if(!(EndElement1.EntryExitNumber()))
17022  {
17023  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
17024  }
17025  EndElement1.CheckCount = 9;
17026  EndElement2.ELinkPos = 1;
17027  EndElement2.XLinkPos = 0;
17028  EndElement2.ELink = EndElement2.Link[1];
17029  EndElement2.XLink = EndElement2.Link[0];
17030  if(!(EndElement2.EntryExitNumber()))
17031  {
17032  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
17033  }
17034  EndElement2.CheckCount = 9; // both now set
17035 
17036 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
17037 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
17038 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
17039 
17040  if(EndElement1.HLoc >= StartElement1.HLoc)
17041  {
17043  SearchLimitHighH = EndElement1.HLoc + 15;
17044  }
17045  else
17046  {
17047  SearchLimitLowH = EndElement1.HLoc - 15;
17049  }
17050  if(EndElement1.VLoc >= StartElement1.VLoc)
17051  {
17053  SearchLimitHighV = EndElement1.VLoc + 15;
17054  }
17055  else
17056  {
17057  SearchLimitLowV = EndElement1.VLoc - 15;
17059  }
17060 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
17061  check & TotalSearchCounts check
17062  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
17063  {
17064  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
17065  Utilities->CallLogPop(1694);
17066  return false;
17067  }
17068 */
17069 // don't need EveryPrefDir check for NonPreferredRoute
17070 
17071 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
17072 // bool InRoute = false;
17074  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17075 
17076  if(RoutePair.first > -1)
17077  {
17078  if(RoutePair.second != 0) // not first element in existing route so no good
17079  {
17080  if(!Callon)
17081  {
17082  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
17083  }
17084  Utilities->CallLogPop(275);
17085  return(false);
17086  }
17087  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
17088 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
17089  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
17090  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
17091  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17092  {
17093  if(!Callon)
17094  {
17095  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
17096  }
17097  Utilities->CallLogPop(276);
17098  return(false);
17099  }
17100  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
17101  EndElement2 = BlankElement; // only need the route element
17102  EndPosition = EndElement1.TrackVectorPosition;
17103  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
17104  }
17105 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
17106  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17107  {
17108  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
17109  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
17110 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17111 // && (AdjPosition != StartRoutePosition))
17112  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17113  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17114  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
17115  {
17116  if(!Callon)
17117  {
17118  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
17119  }
17120  Utilities->CallLogPop(277);
17121  return(false);
17122  }
17123 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
17124 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
17125  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
17126  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17127  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
17128  (AdjPosition != StartRoutePosition))
17129  {
17130  if(!Callon)
17131  {
17132  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
17133  }
17134  Utilities->CallLogPop(278);
17135  return(false);
17136  }
17137 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
17139  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
17140  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
17141  {
17142  if(!Callon)
17143  {
17144  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
17145  }
17146  Utilities->CallLogPop(279);
17147  return(false);
17148  }
17149  }
17150 
17151 // check for same route as start element
17153  {
17154  if(!Callon)
17155  {
17156  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
17157  }
17158  Utilities->CallLogPop(280);
17159  return(false);
17160  }
17161 // check for a looping route
17162  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
17163  {
17165  {
17166  if(!Callon)
17167  {
17168  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
17169  }
17170  Utilities->CallLogPop(1845);
17171  return(false);
17172  }
17173  }
17174 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
17175 // so search from this element.
17176 
17177  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
17178 
17179  if(StartSelectionRouteID > -1)
17180  {
17181  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
17182  {
17184  if(PointsToBeChanged(0, NewFailedPointsTVPos))
17185  {
17186  if(NewFailedPointsTVPos > -1)
17187  {
17188  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
17189  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
17190  " failed during route setting.");
17191  Utilities->CallLogPop(2504);
17192  return(false);
17193  }
17194  PointsChanged = true;
17195  }
17196  Utilities->CallLogPop(281);
17197  return(true);
17198  }
17199  else
17200  {
17201  if(!Callon && !Track->SuppressRouteFailMessage)
17202  {
17204  }
17205  Utilities->CallLogPop(282);
17206  return(false);
17207  }
17208  }
17209  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
17210  // search on the 2 ways out of the element, which has to be a 2-ended element
17211  {
17212 // check if selection adjacent to start element and if so use that
17213  if(SearchVector.at(0).Conn[0] == EndPosition)
17214  {
17215  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
17216  {
17218  if(PointsToBeChanged(1, NewFailedPointsTVPos))
17219  {
17220  if(NewFailedPointsTVPos > -1)
17221  {
17222  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
17223  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
17224  " failed during route setting.");
17225  Utilities->CallLogPop(2506);
17226  return(false);
17227  }
17228  PointsChanged = true;
17229  }
17230  Utilities->CallLogPop(283);
17231  return(true);
17232  }
17233  else
17234  {
17235  if(!Callon && !Track->SuppressRouteFailMessage)
17236  {
17238  }
17239  Utilities->CallLogPop(284);
17240  return(false);
17241  }
17242  }
17243  else if(SearchVector.at(0).Conn[1] == EndPosition)
17244  {
17245  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
17246  {
17248  if(PointsToBeChanged(2, NewFailedPointsTVPos))
17249  {
17250  if(NewFailedPointsTVPos > -1)
17251  {
17252  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
17253  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
17254  " failed during route setting.");
17255  Utilities->CallLogPop(2508);
17256  return(false);
17257  }
17258  PointsChanged = true;
17259  }
17260  Utilities->CallLogPop(285);
17261  return(true);
17262  }
17263  else
17264  {
17265  if(!Callon && !Track->SuppressRouteFailMessage)
17266  {
17268  }
17269  Utilities->CallLogPop(286);
17270  return(false);
17271  }
17272  }
17273  // now start off in the best direction
17274  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
17275 
17276  if(SearchVector.at(0).Config[BestPos] != End)
17277  {
17278  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17279  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
17280  {
17282  if(PointsToBeChanged(3, NewFailedPointsTVPos))
17283  {
17284  if(NewFailedPointsTVPos > -1)
17285  {
17286  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
17287  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
17288  " failed during route setting.");
17289  Utilities->CallLogPop(2510);
17290  return(false);
17291  }
17292  PointsChanged = true;
17293  }
17294  Utilities->CallLogPop(287);
17295  return(true);
17296  }
17297  }
17298  if(SearchVector.at(0).Config[1 - BestPos] != End)
17299  {
17300  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17301  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
17302  {
17304  if(PointsToBeChanged(4, NewFailedPointsTVPos))
17305  {
17306  if(NewFailedPointsTVPos > -1)
17307  {
17308  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
17309  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
17310  " failed during route setting.");
17311  Utilities->CallLogPop(2512);
17312  return(false);
17313  }
17314  PointsChanged = true;
17315  }
17316  Utilities->CallLogPop(288);
17317  return(true);
17318  }
17319  }
17320  }
17321  if(!Callon && !Track->SuppressRouteFailMessage)
17322  {
17324  }
17325  Utilities->CallLogPop(289);
17326  return(false);
17327 }
17328 
17329 // ---------------------------------------------------------------------------
17330 
17331 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
17332 /*
17333  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
17334  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
17335  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
17336  Keep a count of entries in SearchVector during the current function call, so that this number can be
17337  erased for an unproductive branch search.
17338  First check (within the loop) whether XLink leads to an End & return false if so.
17339  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
17340  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
17341  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
17342  train on element (unless a bridge & train on different track), or if element
17343  fouls an existing diagonal route (except if element is a leading point - these checked later).
17344  Then check if found required element. If so save it & return true.
17345  If not the required element check if buffer or continuation, & if so erase all searchvector
17346  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
17347  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
17348  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
17349  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
17350  When return true have 8 items from CheckCount established, only waiting for EXNumber
17351 */
17352 {
17353  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
17354  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
17355  int VectorCount = 0;
17356 
17357 // check for a fouled diagonal for first element. Added for v1.3.2
17358  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
17359  (CurrentTrackElement.Link[XLinkPos] == 9))
17360  {
17361  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
17362  {
17363  for(int x = 0; x < VectorCount; x++)
17364  {
17365  SearchVector.erase(SearchVector.end() - 1);
17366  }
17367  Utilities->CallLogPop(2044);
17368  return(false);
17369  }
17370  }
17371  while(true)
17372  {
17373  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
17374  {
17375  for(int x = 0; x < VectorCount; x++)
17376  {
17377  SearchVector.erase(SearchVector.end() - 1);
17378  }
17379  Utilities->CallLogPop(1927);
17380  return(false);
17381  }
17382  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
17383  {
17384  for(int x = 0; x < VectorCount; x++)
17385  {
17386  SearchVector.erase(SearchVector.end() - 1);
17387  }
17388  Utilities->CallLogPop(290);
17389  return(false);
17390  }
17391  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
17392  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
17393  TPrefDirElement SearchElement(NextTrackElement);
17394  SearchElement.TrackVectorPosition = NextPosition;
17395  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
17396  SearchElement.ELinkPos = NextELinkPos;
17397  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
17398  int NextXLinkPos;
17399  if(SearchElement.ELinkPos == 0)
17400  {
17401  NextXLinkPos = 1;
17402  }
17403  if(SearchElement.ELinkPos == 1)
17404  {
17405  NextXLinkPos = 0;
17406  }
17407  if(SearchElement.ELinkPos == 2)
17408  {
17409  NextXLinkPos = 3;
17410  }
17411  if(SearchElement.ELinkPos == 3)
17412  {
17413  NextXLinkPos = 2;
17414  }
17415  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
17416  {
17417  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
17418  // but may be buffers, continuation or gap
17419  SearchElement.XLinkPos = NextXLinkPos;
17420  }
17421 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
17422 // can't set XLink or XLinkPos yet if the element is a leading point.
17423 
17424 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
17425  drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of crossovers as can reach
17426  element on opposite track and still find the required end point - causes error when adding to the Route"MultiMap (happened by chance when
17427  developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search through all searchvector.
17428 
17429  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
17430 */
17431  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
17432  {
17433  for(unsigned int x = 0; x < SearchVector.size(); x++)
17434  {
17435  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
17436  {
17437  for(int x = 0; x < VectorCount; x++)
17438  {
17439  SearchVector.erase(SearchVector.end() - 1);
17440  }
17441  Utilities->CallLogPop(2655);
17442  return(false);
17443  }
17444  }
17445  }
17446  else if(SearchElement.TrackType == Bridge)
17447  {
17448  for(unsigned int x = 0; x < SearchVector.size(); x++)
17449  {
17450  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
17451  (SearchElement.ELink == SearchVector.at(x).ELink))
17452  {
17453  for(int x = 0; x < VectorCount; x++)
17454  {
17455  SearchVector.erase(SearchVector.end() - 1);
17456  }
17457  Utilities->CallLogPop(2656);
17458  return(false);
17459  }
17460  }
17461  }
17462 
17463 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
17464  TAllRoutes::TRouteElementPair SecondPair;
17466  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
17467  if(RoutePair.first > -1)
17468  {
17469  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
17470  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
17471  RoutePair.second).ELinkPos)))
17472  {
17473  // still OK if start of an expected route
17474  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
17475  {
17476  for(int x = 0; x < VectorCount; x++)
17477  {
17478  SearchVector.erase(SearchVector.end() - 1);
17479  }
17480  Utilities->CallLogPop(292);
17481  return(false); // only allow for start of an expected route
17482  }
17483  }
17484  }
17485  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
17486  {
17487  // OK if it's a bridge & routes on different tracks
17488  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
17489  SecondPair.second).ELinkPos)))
17490  {
17491  // still OK if start of an expected route
17492  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
17493  {
17494  for(int x = 0; x < VectorCount; x++)
17495  {
17496  SearchVector.erase(SearchVector.end() - 1);
17497  }
17498  Utilities->CallLogPop(293);
17499  return(false); // only allow for start of an expected route
17500  }
17501  }
17502  }
17503 // check if a train on element, unless a bridge & train on different track
17504 // OK of same train as start element - no, drop this
17505 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
17506  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
17507  {
17508  for(int x = 0; x < VectorCount; x++)
17509  {
17510  SearchVector.erase(SearchVector.end() - 1);
17511  }
17512  Utilities->CallLogPop(294);
17513  return(false);
17514  }
17515  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
17516  {
17517  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
17518  {
17519  for(int x = 0; x < VectorCount; x++)
17520  {
17521  SearchVector.erase(SearchVector.end() - 1);
17522  }
17523  Utilities->CallLogPop(295);
17524  return(false);
17525  }
17526  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
17527  {
17528  for(int x = 0; x < VectorCount; x++)
17529  {
17530  SearchVector.erase(SearchVector.end() - 1);
17531  }
17532  Utilities->CallLogPop(296);
17533  return(false);
17534  }
17535  }
17536 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
17537  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17538  {
17539  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17540  {
17541  for(int x = 0; x < VectorCount; x++)
17542  {
17543  SearchVector.erase(SearchVector.end() - 1);
17544  }
17545  Utilities->CallLogPop(297);
17546  return(false);
17547  }
17548  }
17549 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
17550 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
17551 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
17553  {
17554  for(int x = 0; x < VectorCount; x++)
17555  {
17556  SearchVector.erase(SearchVector.end() - 1);
17557  }
17558  Utilities->CallLogPop(1689);
17559  return(false);
17560  }
17561 // check if found it
17562  if(SearchElement.TrackVectorPosition == RequiredPosition)
17563  {
17564  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
17565  {
17566  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
17567  {
17568  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
17569  }
17570  else
17571  {
17572  SearchElement.XLinkPos = 1;
17573  }
17574 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
17575  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
17576  }
17577  SearchVector.push_back(SearchElement);
17578  VectorCount++; // not really needed but include for tidyness
17579  TotalSearchCount++;
17580  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
17581  {
17582  for(int x = 0; x < VectorCount; x++)
17583  {
17584  SearchVector.erase(SearchVector.end() - 1);
17585  }
17586  Utilities->CallLogPop(2525);
17587  return(false);
17588  }
17589  Utilities->CallLogPop(298);
17590  return(true);
17591  }
17592 // Not the required element - check if a buffer or continuation
17593  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
17594  {
17595  for(int x = 0; x < VectorCount; x++)
17596  {
17597  SearchVector.erase(SearchVector.end() - 1);
17598  }
17599  Utilities->CallLogPop(299);
17600  return(false);
17601  }
17602 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
17604  {
17605  for(int x = 0; x < VectorCount; x++)
17606  {
17607  SearchVector.erase(SearchVector.end() - 1);
17608  }
17609  Utilities->CallLogPop(1421);
17610  return(false);
17611  }
17612 //deal with failed points, added at v2.13.0
17613  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
17614  {
17615  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
17616  {
17617  SearchElement.XLinkPos = 1;
17618  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17619  }
17620  else
17621  {
17622  SearchElement.XLinkPos = 3;
17623  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
17624  }
17625  }
17626  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
17627  {
17628  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
17629  {
17630  for(int x = 0; x < VectorCount; x++)
17631  {
17632  SearchVector.erase(SearchVector.end() - 1);
17633  }
17634  Utilities->CallLogPop(2533);
17635  return(false);
17636  }
17637  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
17638  {
17639  for(int x = 0; x < VectorCount; x++)
17640  {
17641  SearchVector.erase(SearchVector.end() - 1);
17642  }
17643  Utilities->CallLogPop(2534);
17644  return(false);
17645  }
17646  }
17647 
17648 // check if reached a non-failed leading point
17649  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
17650  { //added !Failed condition at v2.13.0 to exclude failed points
17651 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
17652  int SearchPos1 = SearchElement.Attribute + 1;
17653  int SearchPos2;
17654  if(SearchPos1 == 2)
17655  {
17656  SearchPos1++;
17657  }
17658  if(SearchPos1 == 1)
17659  {
17660  SearchPos2 = 3;
17661  }
17662  else
17663  {
17664  SearchPos2 = 1;
17665  }
17666 // push element with XLink set to position [SearchPos1]
17667  SearchElement.XLink = SearchElement.Link[SearchPos1];
17668  SearchElement.XLinkPos = SearchPos1;
17669 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
17670  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17671  {
17672  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17673  {
17674  for(int x = 0; x < VectorCount; x++)
17675  {
17676  SearchVector.erase(SearchVector.end() - 1);
17677  }
17678  Utilities->CallLogPop(300);
17679  return(false);
17680  }
17681  }
17682  SearchVector.push_back(SearchElement);
17683  VectorCount++;
17684  TotalSearchCount++;
17685 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
17686 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
17687 // recursive search as has to be a TTrackElement for non-preferred route searches
17688  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
17689  {
17690  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
17691  {
17692  for(int x = 0; x < VectorCount; x++)
17693  {
17694  SearchVector.erase(SearchVector.end() - 1);
17695  }
17696  Utilities->CallLogPop(2526);
17697  return(false);
17698  }
17699  Utilities->CallLogPop(301);
17700  return(true);
17701  }
17702  else
17703  {
17704 // remove leading point with XLinkPos [SearchPos1]
17705  SearchVector.erase(SearchVector.end() - 1);
17706  VectorCount--;
17707 // push element with XLink set to position [SearchPos2]
17708  SearchElement.XLink = SearchElement.Link[SearchPos2];
17709  SearchElement.XLinkPos = SearchPos2;
17710 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
17711  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17712  {
17713  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17714  {
17715  for(int x = 0; x < VectorCount; x++)
17716  {
17717  SearchVector.erase(SearchVector.end() - 1);
17718  }
17719  Utilities->CallLogPop(302);
17720  return(false);
17721  }
17722  }
17723  SearchVector.push_back(SearchElement);
17724  VectorCount++;
17725  TotalSearchCount++;
17726 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
17727  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
17728  {
17729  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
17730  {
17731  for(int x = 0; x < VectorCount; x++)
17732  {
17733  SearchVector.erase(SearchVector.end() - 1);
17734  }
17735  Utilities->CallLogPop(2527);
17736  return(false);
17737  }
17738  Utilities->CallLogPop(303);
17739  return(true);
17740  }
17741  else
17742  {
17743  for(int x = 0; x < VectorCount; x++)
17744  {
17745  SearchVector.erase(SearchVector.end() - 1);
17746  }
17747  Utilities->CallLogPop(304);
17748  return(false);
17749  }
17750  }
17751  } // if leading point
17752 
17753 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
17754 // ready for next element on route
17755  SearchVector.push_back(SearchElement);
17756  VectorCount++;
17757  TotalSearchCount++;
17758  CurrentTrackElement = SearchElement;
17759  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
17760  } // while(true)
17761 }
17762 
17763 // ---------------------------------------------------------------------------
17764 
17766 
17767 /*
17768  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
17769  having all values set (since not necessarily on PrefDirs).
17770  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
17771  (if it was the start), so these are checked first and set if necessary. All elements now have
17772  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
17773  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
17774  to set the route colour and direction graphics.
17775 */
17776 
17777 {
17778  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
17779  if(SearchVector.size() == 0)
17780  {
17781  throw Exception("Error, SearchVector empty");
17782  }
17783 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
17784 // hence need to examine and update it if necessary
17785  TPrefDirElement SecondElement;
17786 
17787  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
17788  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
17789  // need above check or SecondElement will fail
17790  {
17791  SecondElement = SearchVector.at(1);
17792  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
17793  for(int x = 0; x < 4; x++)
17794  {
17795  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
17796  {
17797  if(SearchVector.at(0).XLink == -1) // i.e. not set
17798  {
17799  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
17800  SearchVector.at(0).XLinkPos = x;
17801  }
17802  int ELinkPos;
17803  if(SearchVector.at(0).XLinkPos == 0)
17804  {
17805  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
17806  }
17807  // linked to 1st searchvector element, & if XLink was set then x may not correspond
17808  if(SearchVector.at(0).XLinkPos == 1)
17809  {
17810  ELinkPos = 0;
17811  }
17812  if(SearchVector.at(0).XLinkPos == 2)
17813  {
17814  ELinkPos = 3;
17815  }
17816  if(SearchVector.at(0).XLinkPos == 3)
17817  {
17818  ELinkPos = 2;
17819  }
17820  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
17821  {
17822  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
17823  SearchVector.at(0).ELinkPos = ELinkPos;
17824  }
17825  break; // no point going any further
17826  }
17827  }
17828  }
17829  for(unsigned int x = 0; x < SearchVector.size(); x++)
17830  {
17831  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
17832 // set EXNumber
17833  if(!(SearchVector.at(x).EntryExitNumber()))
17834  {
17835  throw Exception("Error in EntryExitNumber 3");
17836  }
17837  SearchVector.at(x).CheckCount++;
17838 // all values now incorporated
17839  }
17840 
17841  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
17842 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
17843 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
17844  Utilities->CallLogPop(305);
17845 }
17846 
17847 // ---------------------------------------------------------------------------
17848 
17850 
17851 /*
17852  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
17853  AutoSigsRoute.
17854  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
17855  beginning or the end.
17856  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
17857  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
17858  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
17859  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
17860  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
17861  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
17862  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
17863 
17864  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
17865  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
17866  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
17867  route at the start.
17868 
17869  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
17870  for the new route and return.
17871 */
17872 
17873 {
17874  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
17875  AnsiString(ReqPosRouteID.GetInt()));
17876  if(SearchVector.size() < 1)
17877  {
17878  Utilities->CallLogPop(306);
17879  return;
17880  }
17881  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
17882  if(!ValidatePrefDir(6))
17883  {
17884  Utilities->CallLogPop(307);
17885  return;
17886  }
17887  TAllRoutes::TLockedRouteClass LockedRouteObject;
17888 
17890  unsigned int TruncatePrefDirPosition = 0;
17891 
17892  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
17893 /* if have ReqPosRouteID:
17894  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
17895  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
17896  then enter the new route into the AllRoutesVector
17897 */
17898  {
17900  {
17901  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
17902  x++) // start at 1 as first element already in SearchVector
17903  {
17905  }
17906  // note that route numbers in map adjusted when ReqPos route cleared
17908  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
17909  // set during ClearRouteDuringRouteBuildingAt)
17911  {
17914  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
17915  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
17916  }
17917  }
17919  {
17920  SearchVector.pop_back();
17921  }
17922  }
17923  if(StartSelectionRouteID > -1)
17924 /* if have StartSelectionRouteID:
17925  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17926  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17927 */
17928  {
17930  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17931  {
17933  {
17934  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
17935  for(unsigned int x = 0; x < SearchVector.size(); x++)
17936  {
17938  RouteNumber, GetFixedSearchElementAt(7, x));
17939  // find & store locked route truncate position in PrefDirVector for later use
17941  {
17942  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
17943  {
17944  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
17945  }
17946  }
17947  }
17949  {
17950  throw Exception("Failed to validate extended route for nonpreferred route");
17951  }
17954  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
17955  // now add the reinstated locked route if required and set signals accordingly
17956  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
17957  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
17958  // that I haven't thought of
17960  {
17961  LockedRouteObject.RouteNumber = RouteNumber;
17962  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17963  // now reset the signals for the locked route
17964  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
17965  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17966  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17967  {
17968  // return all signals to red in route section to be truncated
17969  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
17970  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
17971  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17972  {
17973  TrackElement.Attribute = 0;
17974  Track->PlotSignal(11, TrackElement, Display);
17975  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17976  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17977  }
17978  }
17979  }
17980  AllRoutes->CheckMapAndRoutes(3); // test
17981  Utilities->CallLogPop(308);
17982  return;
17983  }
17984  }
17985  else
17986  {
17988  }
17989 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17990 // hence nothing to do here
17991  }
17992  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
17993  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
17994  {
17995  throw Exception("Failed to validate single route for nonpreferred route");
17996  }
17997  AllRoutes->StoreOneRoute(2, this);
17998  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
17999  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
18000  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
18001  AllRoutes->CheckMapAndRoutes(4); // test
18002  Utilities->CallLogPop(309);
18003 }
18004 
18005 // ---------------------------------------------------------------------------
18006 
18007 void TOneRoute::SetRoutePoints(int Caller) const
18008 /*
18009  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
18010  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
18011  when they were created.
18012 */
18013 {
18014  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
18015  if(!PrefDirVector.empty())
18016  {
18017  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18018  {
18019  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
18020  {
18021  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
18022  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
18023  }
18024  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
18025  {
18026  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
18027  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
18028  }
18029  }
18030  }
18031  Utilities->CallLogPop(327);
18032 }
18033 
18034 // ---------------------------------------------------------------------------
18035 
18036 void TOneRoute::SetRouteSignals(int Caller) const
18037 // Used for new train additions in AddTrain and in route setting, major changes at v2.17.0
18038 
18039 {
18040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
18041  if(!PrefDirVector.empty())
18042  {
18043  int RouteNumber;
18044  int Attribute = 0;
18045  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
18046  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
18047  if(RouteType != TAllRoutes::NoRoute)
18048  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
18049  {
18050  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
18051  }
18052  }
18053  Utilities->CallLogPop(1720);
18054 }
18055 
18056 // ---------------------------------------------------------------------------
18057 
18058 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
18059 {
18060  //true if at any point in SearchVector points have to be changed,
18061  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
18062  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
18063  NewFailedPointsTVPos = -1; //default value for no new failure
18064  bool PointsChanged = false;
18065  if(!SearchVector.empty())
18066  {
18067  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
18068  {
18069  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
18070  //check for an existing failed point where needs to change to make the route
18071  int Attr = TE.Attribute;
18072  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
18073  {
18074  if(Attr == 1) //currently set to diverge
18075  {
18076  //here add new failure possibility at v2.13.0
18077  if(Utilities->FailureMode != FNil)
18078  {
18079  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18080  {
18082  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18083  IFE.TVPos = NewFailedPointsTVPos;
18084  TE.Failed = true;
18085  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18087  TE.SpeedLimit01 = 10; //values while failed
18088  TE.SpeedLimit23 = 10;
18089  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18090  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18091  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18092  //set repair time, random value in minutes between 10 and 179
18093  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18094  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18095  IFE.RepairTime = RepairTime;
18097  Track->FailedPointsVector.push_back(IFE);
18098  Utilities->CallLogPop(1717);
18099  return(true); //return so only allow one failure per route
18100  }
18101  }
18102  PointsChanged = true; //this is used for setting the flash time
18103  }
18104  }
18105  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
18106  {
18107  if(Attr == 0) //currently set to go straight
18108  {
18109  //here add failure possibility at v2.13.0
18110  if(Utilities->FailureMode != FNil)
18111  {
18112  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18113  {
18115  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18116  IFE.TVPos = NewFailedPointsTVPos;
18117  TE.Failed= true;
18118  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18120  TE.SpeedLimit01 = 10; //values while failed
18121  TE.SpeedLimit23 = 10;
18122  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18123  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18124  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18125  //set repair time, random value in minutes between 10 and 179
18126  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
18127  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18128  IFE.RepairTime = RepairTime;
18130  Track->FailedPointsVector.push_back(IFE);
18131  Utilities->CallLogPop(1718);
18132  return(true); //only allow one failure per route
18133  }
18134  }
18135  PointsChanged = true;
18136  }
18137  }
18138  }
18139  }
18140  Utilities->CallLogPop(1719);
18141  return(PointsChanged);
18142 }
18143 
18144 // ---------------------------------------------------------------------------
18145 
18146 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
18147 /* //added StartPos at v2.17.0 so it starts in the current route
18148 
18149  Only called by SetRearwardsSignalsReturnFalseForTrainInRear
18150 
18151  Works forward through the route from & including StartPos until finds:-
18152  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18153  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
18154  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
18155  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18156  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
18157  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18158  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18159  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18160  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
18161 */
18162 {
18163  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
18164  Attribute = 0;
18165  NextForwardLinkedRouteNumber = -1;
18166  for(unsigned int x = StartPos; x < PrefDirSize(); x++)
18167  {
18168  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
18169  if(PrefDirVector.at(x).TrackType == Bridge)
18170  {
18171  if(PrefDirVector.at(x).XLinkPos < 2)
18172  {
18173  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18174  }
18175  else
18176  {
18177  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18178  }
18179  }
18180  if(TrainID != -1)
18181  {
18182  Utilities->CallLogPop(328); //attribute still 0
18183  return(true);
18184  }
18185  if(PrefDirVector.at(x).TrackType == Buffers)
18186  {
18187  Attribute = 1;
18188  Utilities->CallLogPop(329);
18189  return(true);
18190  }
18191  if(PrefDirVector.at(x).TrackType == Continuation)
18192  {
18193  Attribute = 3;
18194  Utilities->CallLogPop(330);
18195  return(true);
18196  }
18197  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18198  {
18199  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18200  {
18201  Attribute = 0;
18202  Utilities->CallLogPop(1950);
18203  return(true);
18204  }
18205  }
18206  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
18207  {
18208  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
18209  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
18210  {
18211  Attribute++;
18212  }
18213  if(Attribute > 3)
18214  {
18215  Attribute = 3;
18216  }
18217  Utilities->CallLogPop(331);
18218  return(true);
18219  }
18220  if(x == PrefDirSize() - 1) //end element and not signal, buffer, continuation or LC, and no train on element
18221  {
18222  TPrefDirElement LastElement = GetFixedPrefDirElementAt(268, x);
18223  NextForwardLinkedRouteNumber = -1;
18224  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(42, Track->TrackElementAt(1579, LastElement.TrackVectorPosition).Conn[LastElement.XLinkPos], Track->TrackElementAt(1580, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos], NextForwardLinkedRouteNumber);
18225 //the above returns a route (or no route) but LinkPos can be entry or exit, so still need to know it's the entry link for the follow-on route to be valid
18226  if(!(RouteType == TAllRoutes::NoRoute)) //probably a forward route but still need to check if it's linked
18227  {
18228  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(227, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(269, 0); //0 is start position
18229  if(NewRoutePDE.ELinkPos == Track->TrackElementAt(1581, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos]) //if it's not then route not linked so there's no forward route
18230  {
18231  Attribute = 0;
18232  Utilities->CallLogPop(332);
18233  return(false);
18234  }
18235  //else there is no forward route, so return true with attribute still 0
18236  }
18237  //else there is no forward route, so return true with attribute still 0
18238  }
18239  }
18240  Utilities->CallLogPop(333); //
18241  return(true);
18242 }
18243 
18244 // ---------------------------------------------------------------------------
18245 
18246 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
18247 /* Major changes at v2.17.0
18248  This function is only called by TAllRoutes::SetAllRearwardsSignals.
18249 
18250  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18251  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18252  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
18253  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
18254  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
18255  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
18256  or (c) truncating a route.
18257 
18258  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18259  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
18260  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
18261  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
18262  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
18263  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
18264  the function returns true.
18265 
18266  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
18267  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18268 */
18269 {
18270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrainInRear," + AnsiString(Attribute) + "," +
18271  AnsiString(PrefDirVectorStartPosition));
18272  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
18273  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
18274 // if no train or closed LC between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
18275 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
18276 
18277  if(!PrefDirVector.empty())
18278  {
18279  if(!SkipForwardLook)
18280  {
18281  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
18282  {
18283  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18284  if(PrefDirPtr->TrackType == Bridge)
18285  {
18286  if(PrefDirPtr->XLinkPos < 2)
18287  {
18288  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18289  }
18290  else
18291  {
18292  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18293  }
18294  }
18295  if(TrainID != -1)
18296  {
18297  SkipForwardLook = true;
18298  break;
18299  }
18300  }
18301  }
18302 
18304  {
18305  SkipForwardLook = true;
18306  }
18307 
18308  int NextForwardLinkedRouteNumber = -1;
18309  if((unsigned int)PrefDirVectorStartPosition == PrefDirSize() - 1) //end element of route
18310  {
18311  TPrefDirElement PDE = GetFixedPrefDirElementAt(267, PrefDirVectorStartPosition);
18313 //the above returns a route (or no route) but LinkPos can be entry or exit, and need to know it's the entry link for the follow-on route to be valid
18314  if(RouteType == TAllRoutes::NoRoute)
18315  {
18316  SkipForwardLook = true; //if there's no linked forward route then skip
18317  if(PrefDirVector.back().TrackType == Buffers)
18318  {
18319  Attribute = 1; // treat buffer as red signal
18320  }
18321  if(PrefDirVector.back().TrackType == Continuation)
18322  { //check if timing out and no train between 1st signal and continuation and if so don't change attribute
18323  bool SetAttributeTo3 = true;
18326  {
18327  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
18328  AutoSigVectorIT++)
18329  {
18330  if(!AllRoutes->AllRoutesVector.empty())
18331  {
18332  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
18333  {
18334  SetAttributeTo3 = false;
18335  Attribute = AutoSigVectorIT->AccessNumber;
18336  break;
18337  }
18338  }
18339  }
18340  }
18341  if(SetAttributeTo3)
18342  {
18343  Attribute = 3; // treat continuation as a green signal
18344  }
18345  }
18346  }
18347  else //startpos still on end element and there is probably a forward route
18348  {
18349  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(228, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(270, 0); //0 is start position
18350  if(NewRoutePDE.ELinkPos != Track->TrackElementAt(1584, PDE.TrackVectorPosition).ConnLinkPos[PDE.XLinkPos]) //if it's not then route not linked so there's no forward route
18351  {
18352  SkipForwardLook = true; //if there's no linked forward route then skip
18353  if(PrefDirVector.back().TrackType == Buffers)
18354  {
18355  Attribute = 1; // treat buffer as red signal
18356  }
18357  if(PrefDirVector.back().TrackType == Continuation)
18358  {
18359  Attribute = 3; // treat continuation as a green signal
18360  }
18361  }
18362  //else there is a forward route, so just continue to examine it below unless SkipForwardLook is true
18363  }
18364  }
18365 
18366  if(!SkipForwardLook)
18367  {
18368  //start from element in front of PrefDirVectorStartPosition, which may be in same or next forward route (if there isn't one then
18369  //SkipForwardLook will be true - see above)
18370  int StartPos;
18371  if((unsigned int)PrefDirVectorStartPosition < (PrefDirSize() - 1))
18372  {
18373  StartPos = PrefDirVectorStartPosition + 1;
18374  }
18375  else
18376  {
18377  StartPos = 0; //start of next forward route
18378  }
18379  if(StartPos > 0) //starting in this route
18380  {
18381  if(!FindForwardTargetSignalAttribute(2, NextForwardLinkedRouteNumber, Attribute, StartPos))// returns false for having to link to next route to continue search
18382  {
18383  StartPos = 0; //reset to 0 for next route
18384  while(!AllRoutes->GetFixedRouteAt(229, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(3, NextForwardLinkedRouteNumber, Attribute, StartPos))
18385  {
18386  continue;
18387  }
18388  }
18389  }
18390  else //starting in next forward route
18391  {
18392  while(!AllRoutes->GetFixedRouteAt(230, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(4, NextForwardLinkedRouteNumber, Attribute, StartPos))
18393  {
18394  continue;
18395  }
18396  }
18397  }
18398 
18399  //now have target attribute (as supplied or modified in forward look) so look backwards to set signals
18400  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18401  {
18402  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18403  if(PrefDirPtr->TrackType == Bridge)
18404  {
18405  if(PrefDirPtr->XLinkPos < 2)
18406  {
18407  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18408  }
18409  else
18410  {
18411  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18412  }
18413  }
18414  if(TrainID != -1)
18415  {
18416  Utilities->CallLogPop(334);
18417  return(false);
18418  }
18419  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
18420  // the attribute to 0 so first signal behind the LC is red
18421  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18422  {
18423  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18424  {
18425  Attribute = 0;
18426  }
18427  }
18428 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
18429 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18430  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
18431  {
18432  if((!AllRoutes->RouteBackTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
18433  PrefDirPtr->PrefDirRoute)
18434  {
18435 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
18436 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
18437  int LockedVecNum = 0; //not used
18438  TPrefDirElement DummyPrefDir; //not used
18439  bool KeepAttributeAt0ForLockedRoute = false;
18440  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
18441  LockedVecNum))
18442  {
18443  Attribute = 0;
18444  KeepAttributeAt0ForLockedRoute = true;
18445  }
18446 //end of v2.9.2 addition
18447 
18448 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
18449  bool NotGroundSignal = false;
18450  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
18451  {
18452  NotGroundSignal = true;
18453  }
18454 
18455  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
18456  {
18457  Attribute = 0; //stays at 0
18458  }
18459 
18460  if(Attribute < 3)
18461  {
18462  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
18463  }
18464  else
18465  {
18466  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
18467  }
18468  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
18469  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
18470  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
18471  {
18472  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18473  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
18474  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18475  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
18476  }
18477  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
18478  { //if groundsignal attrib is 0 then do need to increment
18479  Attribute++; //this is for the next signal rearwards, not the current one
18480  }
18481 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
18482  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
18483  }
18484  }
18485  }
18486  }
18487  Utilities->CallLogPop(335);
18488  return(true);
18489 }
18490 
18491 // ---------------------------------------------------------------------------
18492 
18493 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
18494 /*
18495  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
18496  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
18497  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
18498  Selection invalid if select a bridge; trying to leave a single element; last element to be left
18499  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
18500  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
18501  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
18502  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
18503 */
18504 {
18505  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18506  "," + AnsiString((short)PrefDirRoute));
18507  bool ElementInRoute = false;
18508  bool MovingTrainOccupyingRoute = false;
18509  unsigned int TruncatePDElementPos; //the selected PD position to truncate to (could be from the back or the front)//added at v2.15.0
18510  enum {NoTruncate, BackTruncate, FrontTruncate, FullTruncate} TruncateType;
18511  TruncateType = NoTruncate;
18513 
18514  for(unsigned int b = 0; b < PrefDirSize(); b++)
18515  {
18516  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
18517  {
18518  TruncatePDElementPos = b;
18519  ElementInRoute = true;
18520  break;
18521  }
18522  }
18523  if(!ElementInRoute)
18524  {
18525  ReturnFlag = NotInRoute;
18526  Utilities->CallLogPop(336);
18527  return;
18528  }
18529 
18530  //now find whether back, front or full truncate //added at v2.15.0
18531  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate
18532  {
18533  if(TruncatePDElementPos == 0)
18534  {
18535  TruncateType = FullTruncate;
18536  AllRoutes->RouteBackTruncateFlag = true; //Added at v2.15.1: FullTruncate is also a form of BackTruncate as far as the flag is concerned for SetAllRearwardsSignals
18537  } //without this, if a non-autosigs route is in front of an autosigs route and runs into buffers or a
18538  else //continuation, and the non-autosigs route is truncated back to the autosigs route (i.e. a full
18539  { //truncate for that route), the last signal in the autosigs route doesn't change to red.
18540  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
18541  if(TempElement.Config[TempElement.XLinkPos] == Signal)
18542  {
18543  TruncateType = FrontTruncate;
18544  }
18545  else
18546  {
18547  TruncateType = BackTruncate;
18549  }
18550  }
18551  }
18552  else // == PrefDirSize() - 1
18553  {
18554  TruncateType = BackTruncate;
18556  }
18557 
18558 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
18559 
18560  if(TruncateType == BackTruncate) //added at v2.15.0
18561  {
18562  for(int b = PrefDirSize() - 1; b >= 0; b--)
18563  {
18564  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18565  if(PrefDirVector.at(b).TrackType == Bridge)
18566  {
18567  if(PrefDirVector.at(b).XLinkPos < 2)
18568  {
18569  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18570  }
18571  else
18572  {
18573  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18574  }
18575  }
18576  if(TrainID != -1)
18577  {
18578  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
18579  {
18580  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18581  }
18582  }
18583  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18584  {
18585  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
18586  ReturnFlag = InRouteFalse;
18588  Utilities->CallLogPop(1941);
18589  return;
18590  }
18591  if(b == int(TruncatePDElementPos))
18592  {
18593  break; // OK found truncate element & no flashing LC in front
18594  }
18595  }
18596  }
18597  else if(TruncateType == FrontTruncate)//front/full truncate //added at v2.15.0
18598  {
18599  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
18600  {
18601  int TrainID = Track->TrackElementAt(1577, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18602  if(PrefDirVector.at(b).TrackType == Bridge)
18603  {
18604  if(PrefDirVector.at(b).XLinkPos < 2)
18605  {
18606  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18607  }
18608  else
18609  {
18610  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18611  }
18612  }
18613  if(TrainID != -1)
18614  {
18615  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
18616  {
18617  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18618  }
18619  }
18620  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18621  {
18622  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
18623  ReturnFlag = InRouteFalse;
18625  Utilities->CallLogPop(2571);
18626  return;
18627  }
18628  if(b == TruncatePDElementPos)
18629  {
18630  break; // OK found truncate element & no flashing LC behind
18631  }
18632  }
18633  }
18634  else //FullTruncate) //added at v2.15.0
18635  {
18636  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
18637  {
18638  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
18639  if(PrefDirVector.at(b).TrackType == Bridge)
18640  {
18641  if(PrefDirVector.at(b).XLinkPos < 2)
18642  {
18643  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18644  }
18645  else
18646  {
18647  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18648  }
18649  }
18650  if(TrainID != -1)
18651  {
18652  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
18653  {
18654  MovingTrainOccupyingRoute = true; // train is behind the truncate point & moving
18655  }
18656  }
18657  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
18658  {
18659  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
18660  ReturnFlag = InRouteFalse;
18662  Utilities->CallLogPop(2572);
18663  return;
18664  }
18665  }
18666  }
18667 
18668  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
18669  {
18670  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
18671  ReturnFlag = InRouteFalse;
18673  Utilities->CallLogPop(338);
18674  return;
18675  }
18676  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
18677  {
18678  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
18679  ReturnFlag = InRouteFalse;
18681  Utilities->CallLogPop(339);
18682  return;
18683  }
18684 
18685  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
18686  {
18687  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
18688  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18689  {
18690  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18691  {
18692  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18693  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18694  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18695  ReturnFlag = InRouteFalse;
18697  Utilities->CallLogPop(340);
18698  return;
18699  }
18700  }
18701  else
18702  {
18703  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18704  {
18705  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
18706  ReturnFlag = InRouteFalse;
18708  Utilities->CallLogPop(341);
18709  return;
18710  }
18711  }
18712  }
18713 
18714  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
18715  {
18716  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
18717  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
18718  {
18719  if(TempElement.Config[TempElement.XLinkPos] != Signal)
18720  {
18721  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18722  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18723  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18724  ReturnFlag = InRouteFalse;
18726  Utilities->CallLogPop(2573);
18727  return;
18728  }
18729  }
18730  else //red route
18731  {
18732  if(TruncatePDElementPos > 0)
18733  {
18734  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
18735  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
18736  {
18737  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
18738  ReturnFlag = InRouteFalse;
18740  Utilities->CallLogPop(2574);
18741  return;
18742  }
18743  }
18744  }
18745  }
18746 
18747  else if(TruncatePDElementPos == 0) //full truncate
18748  {
18749  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
18750  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
18751  {
18752  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
18753  {
18754  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
18755  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
18756  "that lies within the route;\n\nor to remove the whole route select the first track element in the route");
18757  ReturnFlag = InRouteFalse;
18759  Utilities->CallLogPop(2575);
18760  return;
18761  }
18762  }
18763  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
18764  {
18765  if(TempElement.TrackType == Bridge)
18766  {
18767  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
18768  ReturnFlag = InRouteFalse;
18770  Utilities->CallLogPop(2576);
18771  return;
18772  }
18773  }
18774  }
18775 
18776  int ThisRouteNumber;
18778 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
18779 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
18780 
18781 // check if part of this route already locked & disallow if so
18782  if(!(AllRoutes->LockedRouteVector.empty()))
18783  {
18785  {
18786  if(LRVIT->RouteNumber == ThisRouteNumber)
18787  {
18788  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
18789  ReturnFlag = InRouteFalse;
18791  Utilities->CallLogPop(749);
18792  return;
18793  }
18794  }
18795  }
18796 
18797  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
18798  if(TruncateType == BackTruncate) //is within 3 running signals on this or linked rearwards routes -m this is a PDElement position
18799  {
18800  LookBackwardsFromHere = TruncatePDElementPos;
18801  }
18802 
18803 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
18804  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
18805  int FrontPosition;
18806 
18807  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
18808  // RouteLockingRequired only checks for trains approaching
18809  {
18812  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
18813  L"Warning!", MB_YESNO | MB_ICONWARNING);
18814  TrainController->BaseTime = TDateTime::CurrentDateTime();
18816  if(button == IDNO)
18817  {
18818  ReturnFlag = InRouteTrue; // still return true even though don't act on it
18820  Utilities->CallLogPop(342);
18821  return;
18822  }
18823  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
18824  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
18825  TAllRoutes::TLockedRouteClass LockedRoute;
18826  bool ExistingLockedRouteModified = false;
18827  LockedRoute.RouteNumber = ThisRouteNumber;
18828  if(TruncateType == BackTruncate)
18829  {
18830  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18831  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18832  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18833  }
18834  else if(TruncateType == FrontTruncate)
18835  {
18836  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18837  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
18838  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
18839  }
18840  else //FullTruncate
18841  {
18842  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
18843  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
18844  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
18845  }
18846 
18847  LockedRoute.LockStartTime = TrainController->TTClockTime;
18848 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
18849 // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
18850  if(!AllRoutes->LockedRouteVector.empty())
18851  {
18852  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
18853  LRVIT++)
18854  {
18855  if(LRVIT->RouteNumber == ThisRouteNumber)
18856  {
18857  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
18858  LRVIT->LockStartTime = LockedRoute.LockStartTime;
18859  ExistingLockedRouteModified = true;
18860  }
18861  }
18862  }
18863  if(!ExistingLockedRouteModified)
18864  {
18865  AllRoutes->LockedRouteVector.push_back(LockedRoute);
18866  }
18867  if(TruncateType == BackTruncate)
18868  {
18869  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
18870  RearPosition = TruncatePDElementPos;
18871  FrontPosition = PrefDirSize() - 1;
18872  }
18873  else if(TruncateType == FrontTruncate)
18874  {
18875  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
18876  RearPosition = 0;
18877  FrontPosition = TruncatePDElementPos;
18878  }
18879  else //FullTruncate
18880  {
18881  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
18882  RearPosition = 0;
18883  FrontPosition = PrefDirSize() - 1;
18884  }
18885 // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
18886  for(int c = FrontPosition; c >= RearPosition; c--)
18887  {
18888  // return all signals to red in route section to be truncated
18889  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
18890  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
18891  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18892  {
18893  TrackElement.Attribute = 0;
18894  Track->PlotSignal(2, TrackElement, Display);
18895  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18896  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18897  }
18898  }
18899 // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
18900  ReturnFlag = InRouteTrue;
18901  }
18902  else //route locking not required
18903  {
18904  if(TruncateType == BackTruncate)
18905  {
18906  RearPosition = TruncatePDElementPos;
18907  FrontPosition = PrefDirSize() - 1;
18908  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
18909  }
18910  else if(TruncateType == FrontTruncate)
18911  {
18912  RearPosition = 0;
18913  FrontPosition = TruncatePDElementPos;
18914  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
18915  }
18916  else
18917  {
18918  RearPosition = 0;
18919  FrontPosition = PrefDirSize() - 1;
18920  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
18921  }
18922 
18923  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
18924  //into adjacent red or green routes if there are any (after the truncation/removal)
18925 
18926  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
18927  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
18928 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
18929 
18930  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
18931  {
18932  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
18933  ReturnFlag = InRouteTrue;
18934  }
18935 
18936  if(LastPDElement.AutoSignals)
18937  {
18938  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
18939  }
18940  }
18941 
18942  AllRoutes->CheckMapAndRoutes(5); // test
18943  ReturnFlag = InRouteTrue;
18945  Utilities->CallLogPop(344);
18946 }
18947 
18948 // ---------------------------------------------------------------------------
18949 
18951 {
18952 /*
18953 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
18954 signal.
18955 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
18956  but a new route that is created TO a signal - that signal becomes part of the new route.
18957 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
18958 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
18959  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
18960  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
18961  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
18962  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
18963  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
18964 */
18965 
18966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
18967  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
18968  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
18969  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
18970  {
18971  Utilities->CallLogPop(2578);
18972  return;
18973  }
18974  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
18975  int RouteColour;
18976  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
18977  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
18978  {
18979  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
18980  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
18981  { //found a linked forward route
18982  //check if signal behind this route has been removed from the blue route
18983  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
18984  { //signal needs to be added at start of this linked route
18985 
18986  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
18987  if(RouteColour == 1) //red route
18988  {
18989  NewRedFirstPDElement = LastPDElement;
18990  NewRedFirstPDElement.AutoSignals = false;
18991  NewRedFirstPDElement.PrefDirRoute = false;
18992  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
18993  NewRedFirstPDElement.IsARoute = true;
18994  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
18995  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
18996  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
18997  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
18998  {
18999  if(R2MMIt->second.first == int(x))
19000  {
19001  R2MMIt->second.second++;
19002  }
19003  }
19004  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
19005  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19006  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
19007  }
19008  else if(RouteColour == 2) //green route
19009  {
19010  NewGreenFirstPDElement = LastPDElement;
19011  NewGreenFirstPDElement.AutoSignals = false;
19012  NewGreenFirstPDElement.PrefDirRoute = true;
19013  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19014  NewGreenFirstPDElement.IsARoute = true;
19015  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
19016  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
19017  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19018  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19019  {
19020  if(R2MMIt->second.first == int(x))
19021  {
19022  R2MMIt->second.second++;
19023  }
19024  }
19025  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
19026  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19027  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
19028  }
19029  }
19030  break; //no point looking any further
19031  }
19032  }
19033 
19034 //check if there's a linked rearward route missing a signal and if so add it
19035  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19036  {
19037  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
19038  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
19039  { //found a linked rearward route
19040  //check if signal in front of this route has been removed from the blue route
19041  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19042  { //signal needs to be added at end of this linked route
19043 
19044  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
19045  if(RouteColour == 1) //red route
19046  {
19047  NewRedLastPDElement = FirstPDElement;
19048  NewRedLastPDElement.AutoSignals = false;
19049  NewRedLastPDElement.PrefDirRoute = false;
19050  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19051  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
19052  //can use this as adding to the end of the route
19053  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19054  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
19055  }
19056  else if(RouteColour == 2) //green route
19057  {
19058  NewGreenLastPDElement = FirstPDElement;
19059  NewGreenLastPDElement.AutoSignals = false;
19060  NewGreenLastPDElement.PrefDirRoute = true;
19061  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19062  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
19063  //can use this as adding to the end of the route
19064  AllRoutes->RouteBackTruncateFlag = false; //no longer truncating at this point
19065  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
19066  }
19067  }
19068  break; //no point looking any further
19069  }
19070  }
19071  Utilities->CallLogPop(2579);
19072 }
19073 
19074 // ---------------------------------------------------------------------------
19075 
19077 /*
19078  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
19079  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
19080  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
19081  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
19082  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
19083  the route colours.
19084 */
19085 {
19086  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
19087  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
19089  int RouteNumber;
19090  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
19091  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
19092  //these added at v2.15.0
19093  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19094  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
19095 
19096  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
19097  {
19098  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
19099  {
19100  if(PrefDirVector.at(x).TrackType == SignalPost)
19101  {
19102  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
19103  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
19104  }
19105  }
19106 // AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0); //dropped at v2.17.0 in favour of setting all signals after route removal (see below)
19107  //Fault found on B'ham when train (2A09) exited from Snow Hill terminal platform (no signal) when orce cancelled
19108  //route above, but when rearwards signals set the route to be cancelled still exists, so setting signals first uses
19109  //forward look when it finds a red signal in the route to be cancelled, so first signal in rear route becames yellow
19110  //when should have been be red.
19111 // already set all signals to red in route so start at start of route for further rearwards signal setting <- comment invalid after above
19112  }
19113  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
19114  {
19115  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
19116  }
19117 
19118  if(LastPDElement.AutoSignals) //added at v2.15.0
19119  {
19120  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
19121  }
19122 
19123  if(AllRoutes->AllRoutesVector.size() > 0) //added at v2.17.0 - see above
19124  {
19125  for(TAllRoutes::TAllRoutesVectorIterator ARVIt = AllRoutes->AllRoutesVector.begin(); ARVIt < AllRoutes->AllRoutesVector.end(); ARVIt++)
19126  {
19127  ARVIt->SetRouteSignals(14);
19128  }
19129  }
19130  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
19131  AllRoutes->CheckMapAndRoutes(9); // test
19132  TrainController->BaseTime = TDateTime::CurrentDateTime();
19134  Utilities->CallLogPop(345);
19135  return;
19136 }
19137 
19138 // ---------------------------------------------------------------------------
19139 
19140 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19141 /*
19142  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
19143 */
19144 {
19145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
19146  AnsiString((short)PrefDirRoute));
19147  if(SearchVector.empty())
19148  {
19149  Utilities->CallLogPop(1149);
19150  return;
19151  }
19152  for(unsigned int b = 0; b < SearchVector.size(); b++)
19153  {
19156  PrefDirRoute);
19157  }
19158  Utilities->CallLogPop(346);
19159 }
19160 
19161 // ---------------------------------------------------------------------------
19162 
19163 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19164 /*
19165  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
19166  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
19167  TOneRoute.
19168 */
19169 {
19170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
19171  AnsiString((short)PrefDirRoute));
19172  RouteFlash.RouteFlashVector.clear();
19173  TRouteFlashElement RouteFlashElement;
19174 
19175  for(unsigned int b = 0; b < SearchVector.size(); b++)
19176  {
19177  int H = GetFixedSearchElementAt(11, b).HLoc;
19178  int V = GetFixedSearchElementAt(12, b).VLoc;
19180  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
19181  RouteFlashElement.HLoc = H;
19182  RouteFlashElement.VLoc = V;
19184  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
19185  }
19186  Utilities->CallLogPop(348);
19187 }
19188 
19189 // ---------------------------------------------------------------------------
19190 
19191 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
19192 {
19193  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
19194  if(!PrefDirVector.empty())
19195  {
19196  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
19197  {
19198  int H = PrefDirPtr->HLoc;
19199  int V = PrefDirPtr->VLoc;
19200  // check for any LCs that are closed to trains & set the flash values and store in the vector
19201  if(Track->IsLCAtHV(39, H, V))
19202  {
19203  if(Track->IsLCBarrierUpAtHV(0, H, V))
19204  {
19205  Track->LCChangeFlag = true;
19206  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
19207  CLC.HLoc = H;
19208  CLC.VLoc = V;
19210  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
19213  if(PrefDirRoute)
19214  {
19215  CLC.TypeOfRoute = 1;
19216  }
19217  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
19218  Track->ChangingLCVector.push_back(CLC);
19219  }
19220  }
19221  }
19222  }
19223  Utilities->CallLogPop(1948);
19224 }
19225 
19226 // ---------------------------------------------------------------------------
19227 
19229 /*
19230  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19231  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
19232  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19233  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19234 */
19235 {
19236  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
19237  if(!OverlayPlotted)
19238  {
19239  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19240  {
19241  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19242  {
19243  continue;
19244  }
19245  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
19246  Display->Update();
19247  }
19248  OverlayPlotted = true;
19249  }
19250  Utilities->CallLogPop(349);
19251 }
19252 
19253 // ---------------------------------------------------------------------------
19254 
19256 /*
19257  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19258  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
19259  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19260  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19261 */
19262 {
19263  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
19264  if(OverlayPlotted)
19265  {
19266  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19267  {
19268  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19269  {
19270  continue;
19271  }
19272  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
19273  Display->Update();
19274  }
19275  OverlayPlotted = false;
19276  }
19277  Utilities->CallLogPop(350);
19278 }
19279 
19280 // ---------------------------------------------------------------------------
19281 
19282 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
19283 {
19284 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
19285 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
19286 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
19287 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
19288 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
19289 messages, and allocate a repair time similar to points)
19290 */
19291 
19292  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
19293  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
19294  {
19295  Utilities->CallLogPop(2528);
19296  return(false);
19297  }
19298  bool FirstSignalFound = false;
19299  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
19300  {
19301  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
19302 //check for a failed point where needs to change to make the route
19303 //shouldn't be any but check to be safe
19304  int Attr = TE.Attribute;
19305  if(PDVIt->TrackType == Points)
19306  {
19307  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
19308  {
19309  if(Attr == 1) //currently set to diverge
19310  {
19311  if(TE.Failed)
19312  {
19313  Utilities->CallLogPop(2529);
19314  return(false); //return without further checking
19315  }
19316  }
19317  }
19318  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
19319  {
19320  if(Attr == 0) //currently set to go straight
19321  {
19322  if(TE.Failed)
19323  {
19324  Utilities->CallLogPop(2530);
19325  return(false); //return without further checking
19326  }
19327  }
19328  }
19329  }
19330  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
19331  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
19332  //the search vector)
19333  int XLinkPosition = PDVIt->XLinkPos;
19334  if(PDVIt->XLinkPos == -1)
19335  {
19336  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
19337  {
19338  for(int x = 0; x < 4; x++)
19339  {
19340  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
19341  {
19342  XLinkPosition = x;
19343  break;
19344  }
19345  }
19346  }
19347  else
19348  {
19349  Utilities->CallLogPop(2549);
19350  return(false); //no point going any further
19351  }
19352  }
19353  if(XLinkPosition > -1) //should be by now but be safe
19354  {
19355  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19356  {
19357  FirstSignalFound = true; //the first signal doesn't change aspect
19358  continue;
19359  }
19360  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19361  {
19362 /*
19363  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
19364  {
19365  continue; //ground signals don't fail
19366  }
19367 */
19368  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
19369  {
19371  IFE.TVPos = PDVIt->TrackVectorPosition;
19372  TE.Failed = true;
19373  TE.Attribute = 0; //stop aspect
19374  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
19375  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
19376  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
19377  " failed when changing aspect.\nTrains can only pass under signaller control.");
19378  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
19379  //set repair time, random value in minutes between 10 and 179
19380  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
19381  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
19382  IFE.RepairTime = RepairTime;
19384  Track->FailedSignalsVector.push_back(IFE);
19386  int RouteNumber; //not used
19387  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
19388  { // 0 for LinkPos ok as a signal so only one track
19389  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
19390  }
19391  Utilities->CallLogPop(2535);
19392  return(true); //return so only allow one failure per route
19393  }
19394  }
19395  }
19396  }
19397  Utilities->CallLogPop(2531);
19398  return(false);
19399 }
19400 
19401 // ---------------------------------------------------------------------------
19402 // ---------------------------------------------------------------------------
19403 
19404 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
19405 {
19406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
19407  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19408  {
19409  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
19410  }
19411  Utilities->CallLogPop(120);
19412  return(AllRoutesVector.at(At));
19413 }
19414 
19415 // ---------------------------------------------------------------------------
19416 
19418 {
19419  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
19420  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19421  {
19422  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
19423  }
19424  Utilities->CallLogPop(121);
19425  return(AllRoutesVector.at(At));
19426 }
19427 
19428 // ---------------------------------------------------------------------------
19429 
19430 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
19431 /*
19432  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
19433 */
19434 {
19435  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
19436  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19437  {
19438  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
19439  }
19440  Utilities->CallLogPop(351);
19441 }
19442 
19443 // ---------------------------------------------------------------------------
19444 
19445 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
19446 {
19447  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
19448  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19449  {
19450  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
19451  }
19452  Utilities->CallLogPop(1706);
19453 }
19454 
19455 // ---------------------------------------------------------------------------
19456 
19457 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
19458 /*
19459  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
19460  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
19461  Messages are given in TruncateRoute. If successful the route is truncated at and including
19462  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
19463  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
19464  length (train length).
19465 */
19466 {
19467  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
19468  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
19469  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19470  {
19471  TTruncateReturnType ReturnFlag;
19472 // used in SetRearwardsSignalsReturnFalseForTrainInRear (called by TruncateRoute) to skip continuation & buffer attribute change
19473  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
19474  if(ReturnFlag == NotInRoute)
19475  {
19476  continue;
19477  }
19478  else if(ReturnFlag == InRouteTrue)
19479  {
19480  Utilities->CallLogPop(352);
19481  return(true);
19482  }
19483  else if(ReturnFlag == InRouteFalse)
19484  {
19485  Utilities->CallLogPop(353);
19486  return(false);
19487  }
19488  }
19489  Utilities->CallLogPop(354);
19490  return(false);
19491 }
19492 
19493 // ---------------------------------------------------------------------------
19494 
19495 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
19496 /*
19497  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
19498  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
19499 */
19500 {
19501  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
19502  AnsiString(LinkPos));
19503  if(TrackVectorPosition == -1) // allows for continuation entries & exits
19504  {
19505  Utilities->CallLogPop(355);
19506  return(false);
19507  }
19508  THVPair Route2MultiMapKeyPair;
19509 
19510  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
19511  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
19512  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19513  TRoute2MultiMapIterator Route2MultiMapIterator;
19514 
19515  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
19516  {
19517  Utilities->CallLogPop(356);
19518  return(false);
19519  }
19520  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
19521  {
19522  Utilities->CallLogPop(1422);
19523  return(true);
19524  }
19525  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
19526  {
19527  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19528 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19529 // realised after writing this that can't be points as would have been covered above, but leave anyway
19530  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
19531  Route2MultiMapIterator->second.second);
19532  EntryLinkPos = PrefDirElement1.ELinkPos;
19533  ExitLinkPos = PrefDirElement1.XLinkPos;
19534  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19535  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19536  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
19537  {
19538  Utilities->CallLogPop(357);
19539  return(true);
19540  }
19541  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
19542  {
19543  Utilities->CallLogPop(358);
19544  return(true);
19545  }
19546  }
19547  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
19548  {
19549  Utilities->CallLogPop(1423);
19550  return(true);
19551  }
19552  Utilities->CallLogPop(363);
19553  return(false); // none found
19554 }
19555 
19556 // ---------------------------------------------------------------------------
19557 
19558 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
19559  Graphics::TBitmap* &EntryDirectionGraphicPtr)
19560 /*
19561  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
19562  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
19563  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
19564  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
19565  for replotting of AutoSigsRoutes.
19566 */
19567 {
19568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
19569  AnsiString(LinkPos));
19570  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19571  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
19572  if(TrackVectorPosition == -1)
19573  {
19574  Utilities->CallLogPop(364);
19575  return(NoRoute); // allows for continuation entries & exits
19576  }
19577  THVPair Route2MultiMapKeyPair;
19578 
19579  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
19580  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
19581  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19582  TRoute2MultiMapIterator Route2MultiMapIterator;
19583 
19584  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19585  {
19586  Utilities->CallLogPop(365);
19587  return(NoRoute); // none found
19588  }
19589  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19590  {
19591  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19592 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19593  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
19594  Route2MultiMapIterator->second.second);
19595  EntryLinkPos = PrefDirElement1.ELinkPos;
19596  ExitLinkPos = PrefDirElement1.XLinkPos;
19597  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19598  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19599  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
19600  {
19601  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19602  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
19603  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19604  {
19605  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19606  }
19607  if(PrefDirElement1.AutoSignals)
19608  {
19609  Utilities->CallLogPop(366);
19610  return(AutoSigsRoute);
19611  }
19612  else
19613  {
19614  Utilities->CallLogPop(367);
19615  return(NotAutoSigsRoute);
19616  }
19617  }
19618  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
19619  {
19620  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
19621  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
19622  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
19623  {
19624  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
19625  }
19626  if(PrefDirElement1.AutoSignals)
19627  {
19628  Utilities->CallLogPop(368);
19629  return(AutoSigsRoute);
19630  }
19631  else
19632  {
19633  Utilities->CallLogPop(369);
19634  return(NotAutoSigsRoute);
19635  }
19636  }
19637  }
19638  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19639  {
19640  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19641  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19642 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19643  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
19644  EntryLinkPos = PrefDirElement2.ELinkPos;
19645  ExitLinkPos = PrefDirElement2.XLinkPos;
19646  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19647  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19648  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
19649  {
19650  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19651  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
19652  {
19653  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19654  }
19655  if(PrefDirElement2.AutoSignals)
19656  {
19657  Utilities->CallLogPop(370);
19658  return(AutoSigsRoute);
19659  }
19660  else
19661  {
19662  Utilities->CallLogPop(371);
19663  return(NotAutoSigsRoute);
19664  }
19665  }
19666  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
19667  {
19668  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
19669  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
19670  {
19671  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
19672  }
19673  if(PrefDirElement2.AutoSignals)
19674  {
19675  Utilities->CallLogPop(372);
19676  return(AutoSigsRoute);
19677  }
19678  else
19679  {
19680  Utilities->CallLogPop(373);
19681  return(NotAutoSigsRoute);
19682  }
19683  }
19684  ItPair.second--; // the second iterator points one past the last matching value
19685  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
19686  EntryLinkPos = PrefDirElement3.ELinkPos;
19687  ExitLinkPos = PrefDirElement3.XLinkPos;
19688  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19689  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19690  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
19691  {
19692  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19693  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
19694  {
19695  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19696  }
19697  if(PrefDirElement3.AutoSignals)
19698  {
19699  Utilities->CallLogPop(374);
19700  return(AutoSigsRoute);
19701  }
19702  else
19703  {
19704  Utilities->CallLogPop(375);
19705  return(NotAutoSigsRoute);
19706  }
19707  }
19708  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
19709  {
19710  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
19711  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
19712  {
19713  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
19714  }
19715  if(PrefDirElement3.AutoSignals)
19716  {
19717  Utilities->CallLogPop(376);
19718  return(AutoSigsRoute);
19719  }
19720  else
19721  {
19722  Utilities->CallLogPop(377);
19723  return(NotAutoSigsRoute);
19724  }
19725  }
19726  }
19727  Utilities->CallLogPop(378);
19728  return(NoRoute); // none found
19729 }
19730 
19731 // ---------------------------------------------------------------------------
19732 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
19733 /*
19734  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
19735  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
19736 */
19737 {
19738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
19739  AnsiString(LinkPos));
19740  if(TrackVectorPosition == -1)
19741  {
19742  RouteNumber = -1;
19743  Utilities->CallLogPop(379);
19744  return(NoRoute); // allows for continuation & buffer entries & exits
19745  }
19746  THVPair Route2MultiMapKeyPair;
19747 
19748  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
19749  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
19750  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
19751  TRoute2MultiMapIterator Route2MultiMapIterator;
19752 
19753  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
19754  {
19755  RouteNumber = -1;
19756  Utilities->CallLogPop(380);
19757  return(NoRoute); // none found
19758  }
19759  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
19760  {
19761  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
19762 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19763  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
19764  Route2MultiMapIterator->second.second);
19765  EntryLinkPos = PrefDirElement1.ELinkPos;
19766  ExitLinkPos = PrefDirElement1.XLinkPos;
19767  EntryLink = PrefDirElement1.Link[EntryLinkPos];
19768  ExitLink = PrefDirElement1.Link[ExitLinkPos];
19769  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
19770  {
19771  RouteNumber = Route2MultiMapIterator->second.first;
19772  if(PrefDirElement1.AutoSignals)
19773  {
19774  Utilities->CallLogPop(381);
19775  return(AutoSigsRoute);
19776  }
19777  else
19778  {
19779  Utilities->CallLogPop(382);
19780  return(NotAutoSigsRoute);
19781  }
19782  }
19783  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
19784  {
19785  RouteNumber = Route2MultiMapIterator->second.first;
19786  if(PrefDirElement1.AutoSignals)
19787  {
19788  Utilities->CallLogPop(383);
19789  return(AutoSigsRoute);
19790  }
19791  else
19792  {
19793  Utilities->CallLogPop(384);
19794  return(NotAutoSigsRoute);
19795  }
19796  }
19797  }
19798  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
19799  {
19800  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
19801  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
19802 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
19803  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
19804  EntryLinkPos = PrefDirElement2.ELinkPos;
19805  ExitLinkPos = PrefDirElement2.XLinkPos;
19806  EntryLink = PrefDirElement2.Link[EntryLinkPos];
19807  ExitLink = PrefDirElement2.Link[ExitLinkPos];
19808  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
19809  {
19810  RouteNumber = ItPair.first->second.first;
19811  if(PrefDirElement2.AutoSignals)
19812  {
19813  Utilities->CallLogPop(385);
19814  return(AutoSigsRoute);
19815  }
19816  else
19817  {
19818  Utilities->CallLogPop(386);
19819  return(NotAutoSigsRoute);
19820  }
19821  }
19822  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
19823  {
19824  RouteNumber = ItPair.first->second.first;
19825  if(PrefDirElement2.AutoSignals)
19826  {
19827  Utilities->CallLogPop(387);
19828  return(AutoSigsRoute);
19829  }
19830  else
19831  {
19832  Utilities->CallLogPop(388);
19833  return(NotAutoSigsRoute);
19834  }
19835  }
19836  ItPair.second--; // the second iterator points one past the last matching value
19837  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
19838  EntryLinkPos = PrefDirElement3.ELinkPos;
19839  ExitLinkPos = PrefDirElement3.XLinkPos;
19840  EntryLink = PrefDirElement3.Link[EntryLinkPos];
19841  ExitLink = PrefDirElement3.Link[ExitLinkPos];
19842  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
19843  {
19844  RouteNumber = ItPair.second->second.first;
19845  if(PrefDirElement3.AutoSignals)
19846  {
19847  Utilities->CallLogPop(389);
19848  return(AutoSigsRoute);
19849  }
19850  else
19851  {
19852  Utilities->CallLogPop(390);
19853  return(NotAutoSigsRoute);
19854  }
19855  }
19856  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
19857  {
19858  RouteNumber = ItPair.second->second.first;
19859  if(PrefDirElement3.AutoSignals)
19860  {
19861  Utilities->CallLogPop(391);
19862  return(AutoSigsRoute);
19863  }
19864  else
19865  {
19866  Utilities->CallLogPop(392);
19867  return(NotAutoSigsRoute);
19868  }
19869  }
19870  }
19871  RouteNumber = -1;
19872  Utilities->CallLogPop(393);
19873  return(NoRoute); // none found
19874 }
19875 
19876 // ---------------------------------------------------------------------------
19877 
19878 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
19879 /*
19880  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
19881  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
19882  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
19883  and Route2MultiMap.
19884 */
19885 {
19886  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
19887  TOneRoute EmptyRoute;
19888 
19889  EmptyRoute.RouteID = NextRouteID;
19890  NextRouteID++;
19891 
19892  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19893  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19894  {
19895  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
19896  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
19897  }
19898  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
19899  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
19900 
19901  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
19902  Utilities->CallLogPop(394);
19903 }
19904 
19905 // ---------------------------------------------------------------------------
19906 
19908 /*
19909  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
19910  that is already in Route is used.
19911 */
19912 {
19913  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
19914  TOneRoute EmptyRoute;
19915 
19916  EmptyRoute.RouteID = Route->RouteID;
19917 
19918  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
19919  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
19920  {
19921  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
19922  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
19923  }
19924  Utilities->CallLogPop(1579);
19925 }
19926 
19927 // ---------------------------------------------------------------------------
19928 
19929 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
19930 /*
19931  When attaching a new route section to an existing route, it is sometimes necessary to erase the
19932  original route and create a new composite route. This function Erases all elements in the route
19933  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
19934  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
19935  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
19936  that are greater than the route number that is removed. The LockedRouteVector as also searched
19937  and if any relate to the route that has been cleared they are erased too, but the fact that one
19938  has been found is recorded so that it can be re-established later.
19939 */
19940 {
19941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
19942  THVPair Route2MultiMapKeyPair;
19943  TRoute2MultiMapEntry Route2MultiMapEntry;
19944  TRoute2MultiMapIterator Route2MultiMapIterator;
19945 
19946 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
19947 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
19948 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
19949 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
19950 // If so the locked route is removed from the locked vector and is lost.
19951  LockedRouteRearTrackVectorPosition = 0;
19952  LockedRouteLastTrackVectorPosition = 0;
19953  LockedRouteLastXLinkPos = 0;
19954  LockedRouteLockStartTime = TDateTime(0);
19955  if(!LockedRouteVector.empty())
19956  {
19957  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
19958  {
19959  if(LRVIT->RouteNumber == RouteNumber)
19960  {
19961  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
19962  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
19963  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
19964  LockedRouteLockStartTime = LRVIT->LockStartTime;
19965  LockedRouteFoundDuringRouteBuilding = true;
19966  LockedRouteVector.erase(LRVIT);
19967  }
19968  }
19969  }
19970  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
19971  {
19972  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
19973  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
19974  }
19975  Utilities->CallLogPop(395);
19976 }
19977 
19978 // ---------------------------------------------------------------------------
19979 
19981  TRoute2MultiMapIterator &Route2MultiMapIterator)
19982 /*
19983  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
19984  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
19985  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
19986  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
19987  are given for failure.
19988 */
19989 {
19990  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
19991  AnsiString(VLoc) + "," + AnsiString(ELink));
19992  TRouteElementPair ReturnPair;
19993 
19994  ReturnPair.first = -1;
19995  ReturnPair.second = 0;
19996  THVPair Route2MultiMapKeyPair;
19997 
19998  Route2MultiMapKeyPair.first = HLoc;
19999  Route2MultiMapKeyPair.second = VLoc;
20000  TRoute2MultiMapEntry Route2MultiMapEntry;
20001 
20002  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20003  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20004 
20005  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20006  Route2MultiMapIterator = ItPair.first;
20007 
20008  if(ItPair.first == ItPair.second)
20009  {
20010  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
20011  }
20012  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
20013  {
20014  ReturnPair.first = ItPair.first->second.first;
20015  ReturnPair.second = ItPair.first->second.second;
20016  Route2MultiMapIterator = ItPair.first;
20017  Utilities->CallLogPop(396);
20018  return(ReturnPair);
20019  }
20020  ItPair.first++;
20021  if(ItPair.first == ItPair.second)
20022  {
20023  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
20024  }
20025  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
20026  {
20027  ReturnPair.first = ItPair.first->second.first;
20028  ReturnPair.second = ItPair.first->second.second;
20029  Route2MultiMapIterator = ItPair.first;
20030  Utilities->CallLogPop(397);
20031  return(ReturnPair);
20032  }
20033  Utilities->CallLogPop(398);
20034  return(ReturnPair);
20035 }
20036 
20037 // ---------------------------------------------------------------------------
20038 
20039 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
20040 /*
20041  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
20042  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
20043  RouteNumber (route position in AllRoutes vector is returned as a reference.
20044  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
20045  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
20046 */
20047 {
20048  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
20049  AnsiString(VLoc) + "," + AnsiString(ELink));
20050  THVPair Route2MultiMapKeyPair;
20051 
20052  Route2MultiMapKeyPair.first = HLoc;
20053  Route2MultiMapKeyPair.second = VLoc;
20054  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20055 
20056  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20057 
20058  if(ItPair.first == ItPair.second)
20059  {
20060  RouteNumber = -1;
20061  Utilities->CallLogPop(2032);
20062  return(false);
20063  }
20064  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
20065  {
20066  RouteNumber = ItPair.first->second.first;
20067  Utilities->CallLogPop(2033);
20068  return(true);
20069  }
20070  ItPair.first++;
20071 
20072  if(ItPair.first == ItPair.second)
20073  {
20074  RouteNumber = -1;
20075  Utilities->CallLogPop(2034);
20076  return(false);
20077  }
20078  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
20079  {
20080  RouteNumber = ItPair.first->second.first;
20081  Utilities->CallLogPop(2035);
20082  return(true);
20083  }
20084  RouteNumber = -1;
20085  Utilities->CallLogPop(2036);
20086  return(false);
20087 }
20088 
20089 // ---------------------------------------------------------------------------
20090 
20091 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
20092 /*
20093  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
20094  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
20095  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
20096  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
20097  Called by TAllRoutes::AddRouteElement.
20098 */
20099 {
20100  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20101  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
20102  THVPair Route2MultiMapKeyPair;
20103 
20104  Route2MultiMapKeyPair.first = HLoc;
20105  Route2MultiMapKeyPair.second = VLoc;
20106  TRoute2MultiMapEntry Route2MultiMapEntry;
20107 
20108  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20109  TRouteElementPair RouteElementPair;
20110 
20111  RouteElementPair.first = RouteNumber;
20112  RouteElementPair.second = RouteElementNumber;
20113  Route2MultiMapEntry.second = RouteElementPair;
20114 
20115  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
20116  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
20117  {
20118  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
20119  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
20120  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
20121  {
20122  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
20123  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
20124  {
20125  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20126  }
20127  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
20128  }
20129  else
20130  // same ELink so have an error
20131  {
20132  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20133  }
20134  }
20135  else
20136  {
20137  Route2MultiMap.insert(Route2MultiMapEntry);
20138  }
20139 // element at H&V not found in map so insert it
20140  Utilities->CallLogPop(399);
20141 }
20142 
20143 // ---------------------------------------------------------------------------
20144 
20146 /*
20147  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
20148  and the second in the reference SecondPair. If there's only one then it's the function return
20149 */
20150 {
20151  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20152  AnsiString(VLoc));
20154 
20155  TempPair.first = -1;
20156  TempPair.second = 0;
20157  SecondPair = TempPair;
20158  TRoute2MultiMapIterator Route2MultiMapIterator;
20159  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
20160  THVPair Route2MultiMapKeyPair;
20161 
20162  Route2MultiMapKeyPair.first = HLoc;
20163  Route2MultiMapKeyPair.second = VLoc;
20164  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20165  {
20166  Utilities->CallLogPop(400);
20167  return(TempPair);
20168  }
20169  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20170  {
20171  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20172  Utilities->CallLogPop(401);
20173  return(Route2MultiMapIterator->second);
20174  }
20175  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20176  {
20177  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20178  TempPair = ItRange.first->second;
20179  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
20180  Utilities->CallLogPop(402);
20181  return(TempPair);
20182  }
20183  Utilities->CallLogPop(403);
20184  return(TempPair);
20185 }
20186 
20187 // ---------------------------------------------------------------------------
20188 
20189 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
20190 /*
20191  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
20192  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
20193 */
20194 {
20195  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
20196  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
20197  {
20198  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
20199  {
20200  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
20201  TAllRoutes::TRouteElementPair SecondPair;
20202  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
20203  if(RouteElementPair.first == -1)
20204  // failed to find element in multimap
20205  {
20206  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
20207  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
20208  }
20209  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
20210  // neither pair has expected route number
20211  {
20212  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20213  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
20214  (AnsiString)Caller);
20215  }
20216  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
20217  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
20218  {
20219  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20220  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
20221  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
20222  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
20223  }
20224  }
20225  }
20226  unsigned int SizeVal = 0;
20227 
20228 // check map and sum of route sizes match
20229  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20230  {
20231  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
20232  }
20233  if(SizeVal != Route2MultiMap.size())
20234  {
20235  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
20236  (AnsiString)Caller);
20237  }
20238  Utilities->CallLogPop(404);
20239  return;
20240 }
20241 
20242 // ---------------------------------------------------------------------------
20243 
20244 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
20245 /*
20246  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
20247  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
20248  exceed that for the erased route. Where this is so the RouteNumber is decremented.
20249 */
20250 {
20251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
20252  if(!Route2MultiMap.empty())
20253  {
20254  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20255  {
20256  if(Route2MultiMapIterator->second.first > RouteNumber)
20257  {
20258  Route2MultiMapIterator->second.first--;
20259  }
20260  }
20261  }
20262  Utilities->CallLogPop(405);
20263 }
20264 
20265 // ---------------------------------------------------------------------------
20266 
20267 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
20268 /*
20269  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
20270  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
20271  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
20272 */
20273 {
20274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
20275  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
20276  if(!Route2MultiMap.empty())
20277  {
20278  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20279  {
20280  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
20281  {
20282  Route2MultiMapIterator->second.second--;
20283  }
20284  }
20285  }
20286  Utilities->CallLogPop(406);
20287 }
20288 
20289 // ---------------------------------------------------------------------------
20290 
20291 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
20292 /*
20293  Erases the route element from Route2MultiMap and from the PrefDirVector.
20294  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
20295  decremented if they are greater than the element number removed, and if the entire route is removed
20296  then the route numbers are also decremented in the map for route numbers that are greater than the route
20297  number that is removed.
20298 */
20299 {
20300  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20301  AnsiString(ELink));
20302  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
20303  TRoute2MultiMapIterator Route2MultiMapIterator;
20304 
20305  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
20306  if(RequiredRoutePair.first == -1)
20307  {
20308  throw Exception("Failed to find route element in RemoveRouteElement");
20309  }
20310  Route2MultiMap.erase(Route2MultiMapIterator);
20311  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
20312 
20313 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
20314  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
20315 
20316  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
20317  {
20318  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
20319  }
20320 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
20321 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
20322 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
20323 // to check if a route element is present, and the element has already been removed from the map - see above.
20324 
20325 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
20326 /*
20327  int LockedVectorNumber = -1;
20328  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
20329  {
20330  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
20331  }
20332 */
20333 
20334 // erase element from route
20335  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
20336 // CheckMapAndRoutes();//test - drop - tested below
20337 
20338 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
20339 // be so as continuation exit is at the end of the route, and truncation is from the end
20341  {
20343  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20344  AutoSigVectorIT--)
20345  {
20346  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
20347  {
20348  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
20349  }
20350  }
20351  }
20352 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
20353 // and adjust all the corresponding route numbers
20354  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
20355  {
20356  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
20357  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
20358  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
20359 
20360 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
20361  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
20362  it is erased then - see TInterface::ApproachLocking
20363 
20364  if(LockedVectorNumber > -1)
20365  {
20366  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
20367  }
20368 */
20369  // decrement route numbers in the locked route vector whether or not this route is a locked route
20370  if(!LockedRouteVector.empty())
20371  {
20372  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20373  {
20374  if(LRVIT->RouteNumber > RequiredRoutePair.first)
20375  {
20376  LRVIT->RouteNumber--;
20377  }
20378  }
20379  }
20381  {
20383  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20384  AutoSigVectorIT--)
20385  {
20386  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
20387  {
20388  AutoSigVectorIT->RouteNumber--;
20389  }
20390  }
20391  }
20392  }
20393  CheckMapAndRoutes(7); // test
20394  Utilities->CallLogPop(407);
20395 }
20396 
20397 // ---------------------------------------------------------------------------
20398 
20399 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
20400 /*
20401  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
20402  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
20403  since that catches all route elements wherever created
20404 */
20405 {
20406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20407  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
20408  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
20409  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
20410  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
20411 } //number is one less than this
20412 
20413 // ---------------------------------------------------------------------------
20414 
20415 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
20416 /*
20417  Enter with signal at TrackVectorElement already set to red by the passing train.
20418  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
20419  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
20420  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
20421  case the function sets no further signals - if rear route is non-autosigs then no route behind train, if autosigs the train will have
20422  set signals in rear as it passed them.
20423 */
20424 {
20425  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
20426  "," + AnsiString(XLinkPos));
20427  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
20428  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
20429 
20430  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
20431  if(RouteElementPair.first == -1)
20432  {
20433  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
20434  }
20435  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
20436 
20437  RequiredPair = RouteElementPair;
20438  if(RouteElement.XLinkPos != XLinkPos)
20439  {
20440  if(SecondPair.first != -1)
20441  {
20442  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
20443  RequiredPair = SecondPair;
20444  if(RouteElement.XLinkPos != XLinkPos)
20445  {
20446  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
20447  }
20448  }
20449  else
20450  {
20451  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
20452  }
20453  }
20454 // new function
20455  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
20456  Utilities->CallLogPop(409);
20457 }
20458 
20459 // ---------------------------------------------------------------------------
20460 
20461 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber) //minor changes at v2.17.0
20462 /*
20463  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
20464  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
20465  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
20466  accordingly, then double yellow, then green (for 4 aspect signals). There are only 3 calls in all for any given route, and the AccessNumber
20467  changes from 0 to 1 to 2 for successive calls.
20468  Initially Attribute is set to AccessNumber to correspond to the first signal attribute to be set, then a number of validity checks
20469  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
20470  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
20471  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals - if rear
20472  route is non-autosigs then no route behind train, if autosigs the train will have set signals in rear as it passes them.
20473 */
20474 {
20475  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
20476  AnsiString(AccessNumber));
20477  TPrefDirElement RouteElement;
20478  int Attribute = AccessNumber; //was +1, but at v2.17.0 access no. increment carried out before set signals so SetRouteSignals works ok whenever called
20479 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
20480  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
20481 
20482  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
20483  {
20484  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
20485  }
20486  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
20487  {
20488  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
20489  }
20490  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
20491  x).XLinkPos] != End)
20492  {
20493  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
20494  }
20495 // new function
20496  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
20497  Utilities->CallLogPop(410);
20498 }
20499 
20500 // ---------------------------------------------------------------------------
20501 
20502 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition) //some changes at v2.17.0
20503 /*
20504  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
20505  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
20506  or (b) in a linked rear route, in which case the function sets no further signals - if rear route is non-autosigs then no route behind train,
20507  if autosigs the train will have set signals in rear as it passed them.
20508 
20509  First call SetRearwardsSignalsReturnFalseForTrainInRear (which is only called by this function) to set signals in route RouteNumber according
20510  to the received or modified (because of the forward look for buffers or continuation etc.) Attribute. If no train is found during this call
20511  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrainInRear for each rearwards linked route (without a forward look)
20512  until either reach the beginning of the last linked route or find a train in a linked rear route. If a train is found in a linked rear route
20513  then the function terminates.
20514 
20515  However if a train is found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrainInRear then need to continue after the
20516  train for an autosigs route or in case had just added a route segment behind a train that now forms part of a single continuous route for a
20517  non-autosigs route, otherwise the signals won't be set behind the train.
20518 
20519  First the route is examined element by element from the RouteStartPosition towards the start of the
20520  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
20521  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
20522  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
20523  found behind the train.
20524 
20525  Description of SetRearwardsSignalsReturnFalseForTrainInRear for reference
20526  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
20527  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
20528  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
20529  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
20530  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
20531  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
20532  or (c) truncating a route.
20533 
20534  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
20535  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
20536  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
20537  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
20538  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
20539  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
20540  the function returns true.
20541 
20542  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
20543  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
20544 */
20545 {
20546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
20547  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
20548  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
20549  int RearwardLinkedRouteNumber;
20550 
20551 // Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes {dropped at v2.17.0 as not used)
20552  bool SkipForwardLook = false; //allow forward look in first call
20553  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(1, Attribute, RouteStartPosition, SkipForwardLook)) // updates
20554  //Attribute to 1+ final signal value in the route for use in further linked routes
20555  {
20556  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1 (no
20557  { //linked rearwards route)
20558  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20559  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute) //keep setting signals on each rear route until find a train or no more routes
20560  {
20561  SkipForwardLook = true; //don't want forward look for subsequent rearwards linked routes
20562  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(2, Attribute, AllRoutes->GetFixedRouteAt(130,
20563  RearwardLinkedRouteNumber).PrefDirSize() - 1, SkipForwardLook)))
20564  {
20565  break;
20566  }
20567  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
20568  }
20569  }
20570  }
20571  else // found a train in this route (in RouteNumber) before the beginning of the route, so need to continue setting signals after the train
20572  {
20573  int TrainID, TrainPosition, BehindTrainPosition;
20574  bool FoundTrain = false, BehindTrain = false;
20575  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
20576  {
20577  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
20578  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
20579  TrainID = TrackElement.TrainIDOnElement;
20580  if(TrackElement.TrackType == Bridge)
20581  {
20582  if(PrefDirElement.XLinkPos < 2)
20583  {
20584  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20585  }
20586  else
20587  {
20588  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20589  }
20590  }
20591  if(TrainID == -1)
20592  {
20593  continue;
20594  }
20595  else
20596  {
20597  FoundTrain = true;
20598  TrainPosition = x;
20599  break;
20600  }
20601  }
20602  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then this route doesn't continue behind the train so can stop.
20603  { //If there is a linked rear route then no need to deal with signals behind train here -
20604  //if rear route is non-autosigs then no route behind train, if autosigs the train will have
20605  //set signals in rear as it passed them.
20606  for(int x = TrainPosition; x >= 0; x--) // now step back from that position until find element behind the train - ignore any
20607  { // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
20608  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
20609  // need the element behind the rearmost train.
20610  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
20611  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
20612  TrainID = TrackElement.TrainIDOnElement;
20613  if(TrackElement.TrackType == Bridge)
20614  {
20615  if(PrefDirElement.XLinkPos < 2)
20616  {
20617  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20618  }
20619  else
20620  {
20621  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20622  }
20623  }
20624  if(TrainID != -1)
20625  {
20626  continue; // still on train
20627  }
20628  else
20629  {
20630  BehindTrain = true;
20631  BehindTrainPosition = x;
20632  break;
20633  }
20634  }
20635  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
20636  // so on for as many trains as there are on this (RouteNumber) route
20637  {
20638  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // Although SkipForwardLook will be false when
20639  //SetRearwardsSignalsReturnFalseForTrainInRear is first called the forward look will find the train so Attribute will be set to 0
20640  } //for rearward signal setting
20641  }
20642  }
20643  Utilities->CallLogPop(411);
20644 }
20645 
20646 // ---------------------------------------------------------------------------
20647 
20648 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
20649 {
20650 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
20651 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
20652 rearmost linked route) - this because train cancels route elements that it touches)
20653 */
20654  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
20655  AnsiString(LookBackwardsFromHere));
20656  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
20657  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
20658  TPrefDirElement PrefDirElement, FirstElement;
20659  TTrackElement TrackElement;
20660  bool ExamineRoute = true;
20661 
20662  while(ExamineRoute)
20663  {
20664  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
20665  {
20666  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
20667  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
20668  TrainID = TrackElement.TrainIDOnElement;
20669  if(TrackElement.TrackType == Bridge)
20670  {
20671  if(PrefDirElement.XLinkPos < 2)
20672  {
20673  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20674  }
20675  else
20676  {
20677  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20678  }
20679  }
20680  if(TrainID > -1)
20681  {
20682  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
20683  {
20684  //any trains further back in route will be protected by the red signal behind the stopped train
20685  Utilities->CallLogPop(412);
20686  return(false);
20687  }
20688  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
20689  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
20690  //other way & can cancel the route
20691  {
20692  Utilities->CallLogPop(2203);
20693  return(false);
20694  }
20695  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
20696  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
20697  }
20698  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
20699  {
20700  if(TrackElement.Attribute == 0)
20701  {
20702  Utilities->CallLogPop(413);
20703  return(false); // OK, red signal in front of a train
20704  }
20705  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
20706  {
20707  SignalCount++;
20708  }
20709  if(SignalCount >= 3)
20710  {
20711  Utilities->CallLogPop(414);
20712  return(false);
20713  }
20714  }
20715  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
20716  // ElinkPos because working back along PrefDir to beginning
20717  {
20718  Utilities->CallLogPop(415);
20719  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
20720  }
20721  }
20722  //now look at linked rearwards routes
20723  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
20724  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
20725  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
20726  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
20727  {
20728  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
20729  ExamineRoute = true;
20730  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
20731  }
20732  else
20733  {
20734  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
20735  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
20736  TrainID = PriorTrackElement.TrainIDOnElement;
20737  if(PriorTrackElement.TrackType == Bridge)
20738  {
20739  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
20740  {
20741  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
20742  }
20743  else
20744  {
20745  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
20746  }
20747  }
20748  if(TrainID > -1)
20749  {
20750  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
20751  {
20752  Utilities->CallLogPop(748);
20753  return(false);
20754  }
20755  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
20756  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
20757  //other way & can cancel the route
20758  {
20759  Utilities->CallLogPop(2204);
20760  return(false);
20761  }
20762  Utilities->CallLogPop(1962);
20763  return(true); //otherwise need to lock the route
20764  }
20765  ExamineRoute = false;
20766  }
20767  }
20768 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
20769 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
20770  Utilities->CallLogPop(416);
20771  return(false);
20772 }
20773 
20774 // ---------------------------------------------------------------------------
20775 
20776 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
20777  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
20778 {
20779  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
20780  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
20781  TPrefDirElement InternalPrefDirElement; // blank element
20782 
20783  PrefDirElement = InternalPrefDirElement;
20784  if(LockedRouteVector.empty())
20785  {
20786  Utilities->CallLogPop(417);
20787  return(false);
20788  }
20789 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
20790 // even if some elements have been removed from the front by a train
20791  bool InLockedRoute = false;
20792 
20793  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20794  {
20795  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
20796  {
20797  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
20798  // doesn't arise)
20799  InLockedRoute = true;
20800  break;
20801  }
20802  }
20803  if(!InLockedRoute)
20804  {
20805  Utilities->CallLogPop(418);
20806  return(false);
20807  }
20808  int RouteNumber, VectorCount = 0;
20809  TRouteType RouteType;
20810 
20811  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20812  {
20813  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
20814  if(RouteType == NoRoute)
20815  {
20816  continue;
20817  }
20818 /* can't use this test with front truncation
20819  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
20820  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
20821  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
20822  {
20823  throw Exception
20824  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
20825  }
20826 */
20827  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
20828  {
20829  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
20830  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
20831  {
20832  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20833  {
20834  PrefDirElement = InternalPrefDirElement;
20835  LockedVectorNumber = VectorCount;
20836  Utilities->CallLogPop(419);
20837  return(true);
20838  }
20839  }
20840  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
20841  {
20842  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
20843  {
20844  PrefDirElement = InternalPrefDirElement;
20845  LockedVectorNumber = VectorCount;
20846  Utilities->CallLogPop(420);
20847  return(true);
20848  }
20849  else
20850  {
20851  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
20852  }
20853  }
20854  }
20855  VectorCount++;
20856  }
20857  Utilities->CallLogPop(421);
20858  return(false);
20859 }
20860 
20861 // ---------------------------------------------------------------------------
20862 
20864 {
20865  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
20866  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20867  {
20868  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
20869  {
20870  Utilities->CallLogPop(963);
20871  return(x);
20872  }
20873  }
20874  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
20875 }
20876 
20877 // ---------------------------------------------------------------------------
20878 
20880 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
20881 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
20882 {
20883  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20884  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20885  {
20886  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
20887  {
20888  Utilities->CallLogPop(2039);
20889  return(true);
20890  }
20891  }
20892  Utilities->CallLogPop(2040);
20893  return(false);
20894 }
20895 
20896 // ---------------------------------------------------------------------------
20897 
20899 {
20900  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
20901  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20902  {
20903  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
20904  {
20905  Utilities->CallLogPop(964);
20906  return(GetFixedRouteAt(159, x));
20907  }
20908  }
20909  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20910 }
20911 
20912 // ---------------------------------------------------------------------------
20913 
20915 {
20916  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
20917  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20918  {
20919  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
20920  {
20921  Utilities->CallLogPop(965);
20922  return(GetModifiableRouteAt(15, x));
20923  }
20924  }
20925  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
20926 }
20927 
20928 // ---------------------------------------------------------------------------
20929 
20930 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
20931 {
20932  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
20933  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
20934  Utilities->SaveFileInt(OutFile, NextRouteID);
20935  for(unsigned int x = 0; x < AllRoutesSize(); x++)
20936  {
20937  TOneRoute OneRoute = GetFixedRouteAt(165, x);
20938  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
20939  OneRoute.SavePrefDirVector(6, OutFile);
20940  }
20941  Utilities->CallLogPop(1442);
20942 }
20943 
20944 // ---------------------------------------------------------------------------
20945 
20946 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
20947 {
20948  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
20949  int NumberOfRoutes;
20950 
20951  NumberOfRoutes = Utilities->LoadFileInt(InFile);
20952  NextRouteID = Utilities->LoadFileInt(InFile);
20953  for(int x = 0; x < NumberOfRoutes; x++)
20954  {
20955  TOneRoute OneRoute; // empty route
20956  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
20957  OneRoute.LoadPrefDir(2, InFile);
20959  {
20960  StoreOneRouteAfterSessionLoad(0, &OneRoute);
20961  }
20962  else
20963  {
20964  Utilities->CallLogPop(1443);
20965  return(false);
20966  }
20967  }
20968  Utilities->CallLogPop(1444);
20969  return(true);
20970 }
20971 
20972 // ---------------------------------------------------------------------------
20973 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
20974 {
20975  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
20976  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
20977 
20978  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
20979  {
20980  Utilities->CallLogPop(1445);
20981  return(false);
20982  }
20983  int NextID = Utilities->LoadFileInt(InFile);
20984 
20985  if((NextID < 0) || (NextID > 1000000))
20986  {
20987  Utilities->CallLogPop(1446);
20988  return(false);
20989  }
20990  for(int x = 0; x < NumberOfRoutes; x++)
20991  {
20992  int RouteID = Utilities->LoadFileInt(InFile);
20993  if((RouteID < 0) || (RouteID > 20000))
20994  {
20995  Utilities->CallLogPop(1447);
20996  return(false);
20997  }
20998  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
20999  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
21000  {
21001  Utilities->CallLogPop(1448);
21002  return(false);
21003  }
21004  }
21005  Utilities->CallLogPop(1449);
21006  return(true);
21007 }
21008 
21009 // ---------------------------------------------------------------------------
21010 
21011 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
21012 {
21013  // return true for a loop
21014  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
21015  AnsiString(StartPosition));
21016  if(EndPosition == StartPosition)
21017  {
21018  Utilities->CallLogPop(1839);
21019  return(true); // shouldn't happen but treat as a loop if does
21020  }
21021 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
21022  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
21023  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
21024 
21025  while(TrackIsInARoute(15, TVPos, LkPos))
21026  {
21027  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
21028  int NewLkPos = -1;
21029  if(NewTVPos > -1)
21030  {
21031  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
21032  if(NewLkPos == -1)
21033  {
21034  Utilities->CallLogPop(1840);
21035  return(true); // shouldn't arise but treat as loop if does
21036  }
21037  }
21038  else // reached a buffer or continuation
21039  {
21040  Utilities->CallLogPop(1841);
21041  return(false);
21042  }
21043 //Error found by Xeon notified by email 13/10/20.
21044 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
21045 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
21046 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
21047 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
21048 //New check added for v2.6.0
21049 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
21050 //as possible in case there are other unforeseen effects.
21051  int RouteNumber; //dummy, not used
21052  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
21053  {
21054  Utilities->CallLogPop(2241);
21055  return(false);
21056  }
21057  //now make the connected element the current element, read across the TV number and determine the exit link
21058  TVPos = NewTVPos;
21059  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
21060  {
21061  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
21062  {
21063  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
21064  {
21065  LkPos = 1;
21066  }
21067  else
21068  {
21069  LkPos = 3;
21070  }
21071  }
21072  else
21073  {
21074  LkPos = 0;
21075  }
21076  }
21077  else
21078  {
21079  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
21080  }
21081  if(TVPos == StartPosition)
21082  {
21083  Utilities->CallLogPop(1842);
21084  return(true); // it is a loop
21085  }
21086  }
21087  Utilities->CallLogPop(1843);
21088  return(false); // reached end of route so not a loop
21089 }
21090 
21091 // ---------------------------------------------------------------------------
21092 
21093 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21094 /*
21095  Track geometry allows diagonals to cross without occupying the same track element, so when
21096  route plotting it is necessary to check if there is an existing route or a train on such a crossing
21097  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
21098  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21099  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21100  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21101  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21102  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21103  Each of these is examined in turn for each route element in the relevant position.
21104 
21105  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
21106  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
21107  that returns false in all cases (including elements & links not present) except train present.
21108 */
21109 {
21110  int TrainID; // not used in this function
21111 
21112  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
21113  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
21114  TPrefDirElement TempPrefDirElement;
21115  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21116 
21117  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
21118  if(FirstPair.first > -1)
21119  {
21120  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
21121  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21122  {
21123  Utilities->CallLogPop(310);
21124  return(true);
21125  }
21126  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21127  {
21128  Utilities->CallLogPop(311);
21129  return(true);
21130  }
21131  }
21132  if(SecondPair.first > -1)
21133  {
21134  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
21135  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21136  {
21137  Utilities->CallLogPop(312);
21138  return(true);
21139  }
21140  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21141  {
21142  Utilities->CallLogPop(313);
21143  return(true);
21144  }
21145  }
21146  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
21147  9, TrainID)))
21148  {
21149  Utilities->CallLogPop(1997);
21150  return(true);
21151  }
21152  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
21153  if(FirstPair.first > -1)
21154  {
21155  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
21156  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21157  {
21158  Utilities->CallLogPop(314);
21159  return(true);
21160  }
21161  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21162  {
21163  Utilities->CallLogPop(315);
21164  return(true);
21165  }
21166  }
21167  if(SecondPair.first > -1)
21168  {
21169  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
21170  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21171  {
21172  Utilities->CallLogPop(316);
21173  return(true);
21174  }
21175  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21176  {
21177  Utilities->CallLogPop(317);
21178  return(true);
21179  }
21180  }
21181  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
21182  9, TrainID)))
21183  {
21184  Utilities->CallLogPop(1998);
21185  return(true);
21186  }
21187  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
21188  if(FirstPair.first > -1)
21189  {
21190  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
21191  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21192  {
21193  Utilities->CallLogPop(318);
21194  return(true);
21195  }
21196  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21197  {
21198  Utilities->CallLogPop(319);
21199  return(true);
21200  }
21201  }
21202  if(SecondPair.first > -1)
21203  {
21204  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
21205  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21206  {
21207  Utilities->CallLogPop(320);
21208  return(true);
21209  }
21210  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21211  {
21212  Utilities->CallLogPop(321);
21213  return(true);
21214  }
21215  }
21216  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
21217  7, TrainID)))
21218  {
21219  Utilities->CallLogPop(1999);
21220  return(true);
21221  }
21222  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
21223  if(FirstPair.first > -1)
21224  {
21225  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
21226  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21227  {
21228  Utilities->CallLogPop(322);
21229  return(true);
21230  }
21231  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21232  {
21233  Utilities->CallLogPop(323);
21234  return(true);
21235  }
21236  }
21237  if(SecondPair.first > -1)
21238  {
21239  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
21240  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21241  {
21242  Utilities->CallLogPop(324);
21243  return(true);
21244  }
21245  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21246  {
21247  Utilities->CallLogPop(325);
21248  return(true);
21249  }
21250  }
21251  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
21252  3, TrainID)))
21253  {
21254  Utilities->CallLogPop(2000);
21255  return(true);
21256  }
21257  Utilities->CallLogPop(326);
21258  return(false);
21259 }
21260 
21261 // ---------------------------------------------------------------------------
21262 
21263 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21264 /*
21265  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
21266  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21267  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21268  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21269  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21270  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21271  Each of these is examined in turn for each route element in the relevant position.
21272 */
21273 {
21274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
21275  "," + AnsiString(DiagonalLinkNumber));
21276  TPrefDirElement TempPrefDirElement;
21277  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21278 
21279  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
21280  if(FirstPair.first > -1)
21281  {
21282  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
21283  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21284  {
21285  Utilities->CallLogPop(2010);
21286  return(true);
21287  }
21288  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21289  {
21290  Utilities->CallLogPop(2011);
21291  return(true);
21292  }
21293  }
21294  if(SecondPair.first > -1)
21295  {
21296  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
21297  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21298  {
21299  Utilities->CallLogPop(2012);
21300  return(true);
21301  }
21302  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21303  {
21304  Utilities->CallLogPop(2013);
21305  return(true);
21306  }
21307  }
21308  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
21309  if(FirstPair.first > -1)
21310  {
21311  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
21312  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21313  {
21314  Utilities->CallLogPop(2014);
21315  return(true);
21316  }
21317  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21318  {
21319  Utilities->CallLogPop(2015);
21320  return(true);
21321  }
21322  }
21323  if(SecondPair.first > -1)
21324  {
21325  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
21326  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21327  {
21328  Utilities->CallLogPop(2016);
21329  return(true);
21330  }
21331  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
21332  {
21333  Utilities->CallLogPop(2017);
21334  return(true);
21335  }
21336  }
21337  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
21338  if(FirstPair.first > -1)
21339  {
21340  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
21341  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21342  {
21343  Utilities->CallLogPop(2018);
21344  return(true);
21345  }
21346  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21347  {
21348  Utilities->CallLogPop(2019);
21349  return(true);
21350  }
21351  }
21352  if(SecondPair.first > -1)
21353  {
21354  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
21355  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21356  {
21357  Utilities->CallLogPop(2020);
21358  return(true);
21359  }
21360  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
21361  {
21362  Utilities->CallLogPop(2021);
21363  return(true);
21364  }
21365  }
21366  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
21367  if(FirstPair.first > -1)
21368  {
21369  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
21370  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21371  {
21372  Utilities->CallLogPop(2022);
21373  return(true);
21374  }
21375  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21376  {
21377  Utilities->CallLogPop(2023);
21378  return(true);
21379  }
21380  }
21381  if(SecondPair.first > -1)
21382  {
21383  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
21384  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
21385  {
21386  Utilities->CallLogPop(2024);
21387  return(true);
21388  }
21389  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
21390  {
21391  Utilities->CallLogPop(2025);
21392  return(true);
21393  }
21394  }
21395  Utilities->CallLogPop(2026);
21396  return(false);
21397 }
21398 
21399 // ---------------------------------------------------------------------------
21400 
21401 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9194
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19495
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1326
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:12235
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:12208
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:439
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4793
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:573
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5668
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:13753
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:83
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:128
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1742
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:814
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:20091
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:92
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10285
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:20502
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1380
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:806
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:14277
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:824
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:437
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:13793
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3843
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:804
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:287
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7480
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:19457
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:97
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1722
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:730
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5820
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7381
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5847
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1536
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:593
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1683
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:67
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1977
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:934
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10738
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:623
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:21263
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:439
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1713
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:70
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:614
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2885
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:558
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:6000
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8408
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
Definition: TrackUnit.h:1546
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:652
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:19929
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:585
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:13532
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7866
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrackElement::StationEntryStopLinkPos3
int StationEntryStopLinkPos3
Definition: TrackUnit.h:153
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:10479
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9661
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:14926
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:16888
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1141
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:20291
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:762
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1663
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:13336
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:161
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4544
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3723
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1560
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8223
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:445
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1046
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4704
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1340
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6664
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:11513
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3599
Unused
@ Unused
Definition: TrackUnit.h:66
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrack::OneStationLongEnoughForSplit
bool OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10987
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1339
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:20776
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2918
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7852
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:228
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:20973
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:581
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9830
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1721
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1558
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1650
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:210
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:742
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:443
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3323
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:16688
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8700
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:13598
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:808
Simple
@ Simple
Definition: TrackUnit.h:66
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:77
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2934
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:732
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1042
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:20039
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1407
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:13849
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3920
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1783
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5960
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:306
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:745
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:382
TTrack::SetNonStationStopLinkEntryPosses
void SetNonStationStopLinkEntryPosses(int Caller)
similar to SetStationEntryStopLinkPosses but for non-station named elements
Definition: TrackUnit.cpp:10501
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:14797
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:117
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12249
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:577
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:633
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7881
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:89
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:66
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:20399
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7627
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:614
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:575
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10843
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1562
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1524
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:715
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:587
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:810
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1416
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6248
End
@ End
Definition: TrackUnit.h:76
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1564
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:625
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:9054
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:570
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10952
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1055
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:305
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:748
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:816
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:125
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:788
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3894
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:875
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:232
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:66
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9795
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1036
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:19445
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:509
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear
bool SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:18246
TAllRoutes::TAllRoutesVectorIterator
std::vector< TOneRoute >::iterator TAllRoutesVectorIterator
Definition: TrackUnit.h:1677
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1091
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1687
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7895
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:675
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:7073
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:650
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:230
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:9093
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:19430
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:67
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:828
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:75
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14566
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:14303
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:236
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:928
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:65
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4629
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1927
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:437
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:788
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:94
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:11716
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:20244
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4889
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:161
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1946
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:798
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:764
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:565
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1746
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:471
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:660
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11961
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:20879
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1053
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2902
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1570
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:15801
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7508
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8890
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7587
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5871
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:697
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:321
TOneRoute::QuitAllRecursiveSearchesFlag
bool QuitAllRecursiveSearchesFlag
< limit to the number of elements searched in attempting to find a route in on leg
Definition: TrackUnit.h:1550
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:688
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:18950
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1342
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:875
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13937
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:13072
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1688
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:86
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1740
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:46
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:794
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13565
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:715
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:19076
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3700
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:170
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:14256
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:12004
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1829
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:940
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:584
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6054
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1029
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:13385
Under
@ Under
Definition: TrackUnit.h:76
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:828
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:629
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:156
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2957
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12261
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12580
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:434
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:135
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:55
Lead
@ Lead
Definition: TrackUnit.h:76
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:119
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5919
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1863
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:14504
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6131
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:894
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5711
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:18493
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6645
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:86
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:95
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1371
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9589
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:714
TTrack::Up
@ Up
Definition: TrackUnit.h:614
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:830
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:588
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10966
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1518
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:379
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8857
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1681
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:760
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:206
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:19163
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1670
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:66
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6531
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:832
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8803
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7536
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10258
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:76
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:575
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:593
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:796
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:19732
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1597
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:13435
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11900
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4713
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:573
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10938
TGraphicElement::Width
int Width
Definition: TrackUnit.h:441
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:20648
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:20863
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:19558
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:802
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:810
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:663
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:15335
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:662
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4202
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2418
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:695
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9729
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks, bool PerformNameSearch)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2160
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:13203
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:794
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:967
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5895
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:20946
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1562
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1552
TAllRoutes::RouteBackTruncateFlag
bool RouteBackTruncateFlag
used to flag the fact that a route is being truncated from the back in order to change the behaviour ...
Definition: TrackUnit.h:1727
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7234
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1066
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1068
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:8067
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:19255
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:663
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7609
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:67
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5516
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:828
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:14326
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:621
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11812
Parapet
@ Parapet
Definition: TrackUnit.h:67
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:19404
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:115
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:275
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9398
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:19228
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:828
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:20267
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:800
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:248
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1071
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:740
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:16464
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:137
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:208
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:12032
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:13130
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1320
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:19191
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:551
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1379
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:875
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1410
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:20415
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:18146
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1720
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1657
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8377
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:591
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:128
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:206
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:19907
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:214
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3037
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:9742
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6425
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:590
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:161
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:167
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:808
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2638
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:204
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1655
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:8031
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12918
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:13696
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:589
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1524
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10875
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8766
IDInt
Definition: TrackUnit.h:500
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2644
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:20914
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4517
TDisplay
Definition: DisplayUnit.h:49
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10625
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5259
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:882
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:443
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:21011
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1155
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9512
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:142
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:573
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:97
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7978
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1321
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:228
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:141
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:14006
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:784
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:212
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:15132
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1725
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:130
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7946
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:635
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:910
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1535
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1661
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TOneRoute::RouteSearchLimitOneLeg
static const int RouteSearchLimitOneLeg
< limit to the total number of elements searched in attempting to find a route
Definition: TrackUnit.h:1548
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1671
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4811
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9338
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:721
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:16494
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1349
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:437
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:14432
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1327
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:14207
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:66
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:19980
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:10189
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11883
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4224
Trail
@ Trail
Definition: TrackUnit.h:76
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:19140
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9571
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1899
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:39
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:18036
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:66
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1062
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7825
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3800
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6151
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:14104
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:593
TTrack::ThisLocationLongEnoughForSplit
bool ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement, int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
checks if the track that the train is on is long enough for a split, returns false if not,...
Definition: TrackUnit.cpp:11258
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9618
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:55
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12961
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:579
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:716
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:437
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:593
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1051
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:794
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3417
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:441
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1555
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:88
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:688
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:742
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1719
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:269
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:21093
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:13901
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1040
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1526
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1044
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:790
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:904
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4772
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:19878
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1752
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8904
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:699
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:124
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:812
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:710
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1381
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:19282
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:717
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:20930
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:583
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1909
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4755
Connection
@ Connection
Definition: TrackUnit.h:76
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3777
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9852
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:17849
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:12190
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:12779
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8830
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:12162
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1049
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:20189
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:20145
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7307
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:568
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11541
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:736
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1408
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:18058
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5939
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:262
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:155
TTrackElement::StationEntryStopLinkPos4
int StationEntryStopLinkPos4
Used for track at platforms ( 1 & 2) and non-station named locations (1 - 4) to mark the train front ...
Definition: TrackUnit.h:153
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:437
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:774
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10312
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:575
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:738
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:752
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:19417
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4921
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2813
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7906
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3179
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:132
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:18007
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:631
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:14696
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:320
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:772
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:696
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1108
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12100
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1321
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:657
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:667
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:12340
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:437
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:100
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1522
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:201
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8953
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:523
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1807
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9135
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:93
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:726
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:14403
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:20898
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:613
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1378
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4435
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:818
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4646
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7769
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2004
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1057
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6571
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:66
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7564
Platform
@ Platform
Definition: TrackUnit.h:66
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1410
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:214
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:669
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:782
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:717
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4671
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:792
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1665
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1064
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12132
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8328
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1334
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9769
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1038
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:11777
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1814
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:105
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1524
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:16915
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7752
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:822
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1526
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:618
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6588
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3677
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:100
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:114
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:586
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:758
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:11703
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:17331
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:683
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:306
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:627
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1074
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:90
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:690
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:826
RouteCall
@ RouteCall
Definition: TrackUnit.h:1327
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12274
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:91
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:76
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:673
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:20461
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:268
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:745
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:11732
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10707
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:678
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:204
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
True if another train on LinkPos track of element at TrackPos, whether bridge or not,...
Definition: TrackUnit.cpp:11670
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6489
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:161
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:15837
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:750
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12286
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1383
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1659
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1579
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:575
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10698
Bridge
@ Bridge
Definition: TrackUnit.h:66
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1321
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:76
Buffers
@ Buffers
Definition: TrackUnit.h:66
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:17765
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:99
CrossConn
@ CrossConn
Definition: TrackUnit.h:76
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:12298
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4583
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:12221
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852
TTrack::OneNonStationLongEnoughForSplit
bool OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName)
As below but here allow points & crossovers.
Definition: TrackUnit.cpp:11094